diff --git a/.rubocop.yml b/.rubocop.yml index 60b9765af..f97588744 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,75 +1,100 @@ +AllCops: + TargetRubyVersion: 2.4 + TargetRailsVersion: 4.2 -inherit_from: - - ./config/rubocop-suse.yml + DisplayCopNames: true + DisplayStyleGuide: false -# TODO: (mssola) only the LDAP class and portusctl require this. -Metrics/ClassLength: - Max: 210 + Exclude: + # Files that are out of our control and that are not excluded in the + # default config of rubocop. + - db/schema.rb + - db/migrate/* + - vendor/**/* -# TODO: (mssola) Some methods are offending this cop. In the SUSE's style guide -# the approach is to use Rubocop's default value. In the near future I will -# fix this. -Metrics/MethodLength: - Max: 252 +# +# Layout +# -# Of course this will fail in spec blocks... Just skip it. +# This is a remnant of old SUSE-style alignment for hashes, The table format +# looks more human readable. +Layout/AlignHash: + EnforcedHashRocketStyle: table + EnforcedColonStyle: table + +# +# Metrics +# + +# The default is just too small. +Metrics/AbcSize: + Max: 30 + +# We will skip it for tests and the Grape API. Metrics/BlockLength: - Max: 200 Exclude: - spec/**/* + - lib/api/**/* + +# NOTE: this could be further trimmed down but the following refactorings are +# needed: +# 1. The Grape API classes should be further modularized (probably in helper +# modules). +# 2. The models regarding the registry have to be modularized. +# 3. LDAP has to be refactored. +Metrics/ClassLength: + Max: 210 -# It's convenient to mix both. This is something that SUSE's style guide does -# not specify, so we take the approach that we were following already. -Style/ClassAndModuleChildren: - Enabled: false +# The default is just too small. A limit of 100 looks reasonable and many other +# projects (including inside of SUSE) are also using this value. +Metrics/LineLength: + Max: 100 -# NOTE: (mssola) This would be nice, but there are too many errors on this for -# now and it's not urgent. I will fix this in the near future. -Style/Documentation: - Enabled: false +# NOTE: this could be further trimmed down but some refactorings will have to be +# done. +Metrics/MethodLength: + Max: 20 -# This forces us to create a new object for no real reason. -Style/MultipleComparison: - Enabled: false +# +# Rails +# -# Doesn't feel right ... -Style/NumericPredicate: - Enabled: false +Rails: + Enabled: true -# TODO: remove this on Rails 5. -Style/InverseMethods: +Rails/SkipsModelValidations: Enabled: false -# NOTE: (mssola) In versions of Ruby higher than 2.1.x, we get -# Lint/ShadowedException in some cases where in 2.1.x it complains if we remove -# such guards. Therefore, we have to disable this cop until we update the -# version of Ruby to be officially supported. -Lint/UnneededDisable: - Enabled: false +# +# Style +# -Style/FrozenStringLiteralComment: +# It's not needed to add documentation for obvious modules or classes. The main +# idea is that documentation will be asked during the review process if needed. +Style/Documentation: Enabled: false -# TODO: move to SUSE's style guide ? -Style/SymbolArray: +# NOTE: this is giving false positives because it assumes some Rails 5 methods +# are available. +Style/InverseMethods: Enabled: false -Rails: - Enabled: true - -Rails/SkipsModelValidations: +# This forces us to create a new object for no real reason. +Style/MultipleComparison: Enabled: false -AllCops: - TargetRubyVersion: 2.4 - TargetRailsVersion: 4.2 +# This is a common SUSE configuration value: the performance difference between +# single and double quotes is no longer there, and so it's better to be +# consistent and force only double quotes. +Style/StringLiterals: + EnforcedStyle: double_quotes - DisplayCopNames: true - DisplayStyleGuide: false +# Same as Style/StringLiterals. +Style/StringLiteralsInInterpolation: + EnforcedStyle: double_quotes - Exclude: - # Files that are out of our control and that are not excluded in the - # default config of rubocop. - - db/schema.rb - - db/migrate/* - - vendor/**/* +# There are some false positives (e.g. "module ::Module", in which we want to +# make sure there are no clashes or misunderstandings). Therefore, we just +# disable this cop. +Style/ClassAndModuleChildren: + Enabled: false diff --git a/.travis.yml b/.travis.yml index 980d0c167..6b34dfe39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ script: - bundle exec rake portus:assets:compile # Ruby tests - - bundle exec rspec spec packaging/suse/portusctl/spec + - bundle exec rspec spec packaging/suse/portusctl/spec --tag ~integration # Style and security checks - bundle exec rubocop -V diff --git a/Gemfile b/Gemfile index 3b6132cf9..9f5bf09c3 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source "https://rubygems.org" gem "active_record_union" diff --git a/Guardfile b/Guardfile index cf3f814b5..1e7e75e1b 100644 --- a/Guardfile +++ b/Guardfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + guard :rspec, all_on_start: false, cmd: "bundle exec rspec" do require "guard/rspec/dsl" dsl = Guard::RSpec::Dsl.new(self) @@ -31,7 +33,7 @@ end guard :rubocop, all_on_start: true do watch(/.+\.rb\z/) - watch(/\Abin\/.+\z/) + watch(%r{\Abin/.+\z}) watch(%r{(?:.+/)?\.rubocop\.yml$}) do |m| File.dirname(m[0]) diff --git a/Rakefile b/Rakefile index dfeba1820..d6d48c57d 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # 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. diff --git a/Vagrantfile b/Vagrantfile index ce51c457f..29f0fa7e5 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # -*- mode: ruby -*- # vi: set ft=ruby : @@ -15,7 +17,7 @@ Vagrant.configure("2") do |config| node.vm.box_check_update = true node.vm.hostname = "registry.test.lan" node.vm.network :private_network, ip: "192.168.1.2", virtualbox__intnet: true - node.vm.network :forwarded_port, host: 44242, guest: 80 + node.vm.network :forwarded_port, host: 44_242, guest: 80 node.vm.provision( "shell", diff --git a/app/controllers/admin/activities_controller.rb b/app/controllers/admin/activities_controller.rb index 9a05bcd36..d2774e53c 100644 --- a/app/controllers/admin/activities_controller.rb +++ b/app/controllers/admin/activities_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "csv" class Admin::ActivitiesController < Admin::BaseController diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 07d5868db..ea1d8e9ac 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Admin::BaseController < ApplicationController before_action :ensure_admin! diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index 3de0b53f4..3ea208b27 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Admin::DashboardController < Admin::BaseController def index @recent_activities = PublicActivity::Activity diff --git a/app/controllers/admin/namespaces_controller.rb b/app/controllers/admin/namespaces_controller.rb index fc6eed516..cdab2bb87 100644 --- a/app/controllers/admin/namespaces_controller.rb +++ b/app/controllers/admin/namespaces_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Admin::NamespacesController < Admin::BaseController def index @special_namespaces = Namespace.where(global: true) diff --git a/app/controllers/admin/registries_controller.rb b/app/controllers/admin/registries_controller.rb index acf2d1ec0..eac6b9ce7 100644 --- a/app/controllers/admin/registries_controller.rb +++ b/app/controllers/admin/registries_controller.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # Allows the creation of exactly one registry. It also allows updating the # "use_ssl" attribute of a given registry. Doing all this is safe because only # admin users will be able to reach this controller. class Admin::RegistriesController < Admin::BaseController - before_action :registry_created, only: [:new, :create] + before_action :registry_created, only: %i[new create] # GET /admin/registries/ def index diff --git a/app/controllers/admin/teams_controller.rb b/app/controllers/admin/teams_controller.rb index e61db9fba..342a6776f 100644 --- a/app/controllers/admin/teams_controller.rb +++ b/app/controllers/admin/teams_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Admin::TeamsController < Admin::BaseController def index @teams = Team.all_non_special.page(params[:page]) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index ffe15ecc0..bfe2698a0 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class Admin::UsersController < Admin::BaseController respond_to :html, :js - before_action :another_user_access, only: [:edit, :update, :destroy] + before_action :another_user_access, only: %i[edit update destroy] def index @users = User.not_portus.order(:username).page(params[:page]) @@ -32,7 +34,7 @@ def edit; end def update return if @user.nil? - attr = params.require(:user).permit([:email, :display_name]) + attr = params.require(:user).permit(%i[email display_name]) if @user.update_attributes(attr) redirect_to admin_users_path, @@ -72,7 +74,7 @@ def toggle_admin private def user_create_params - permitted = [:username, :email, :password, :password_confirmation] + permitted = %i[username email password password_confirmation] params.require(:user).permit(permitted) end diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 8fedbd39a..299f8a87f 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Api::BaseController < ActionController::Base class ScopeNotHandled < StandardError; end class RegistryNotHandled < StandardError; end diff --git a/app/controllers/api/v2/events_controller.rb b/app/controllers/api/v2/events_controller.rb index 0a9a1f9dc..4fbae5048 100644 --- a/app/controllers/api/v2/events_controller.rb +++ b/app/controllers/api/v2/events_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This is the endpoint being used to handle notifications from the Registry. class Api::V2::EventsController < Api::BaseController # A new notification is coming, register it if valid. diff --git a/app/controllers/api/v2/ping_controller.rb b/app/controllers/api/v2/ping_controller.rb index 689516d94..ea190160c 100644 --- a/app/controllers/api/v2/ping_controller.rb +++ b/app/controllers/api/v2/ping_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Api::V2::PingController < Api::BaseController def ping authenticate_user! diff --git a/app/controllers/api/v2/tokens_controller.rb b/app/controllers/api/v2/tokens_controller.rb index b666ec2cf..6a45ee28e 100644 --- a/app/controllers/api/v2/tokens_controller.rb +++ b/app/controllers/api/v2/tokens_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # TokensController is used to deliver the token that the docker client should # use in order to perform operation into the registry. This is the last step in # the authentication process for Portus' point of view. @@ -49,27 +51,11 @@ def authorize_scopes(registry) scopes.each do |scope| auth_scope, actions = scope_handler(registry, scope) - actions.each do |action| - # It will try to check if the current user is authorized to access the - # scope given in this iteration. If everything is fine, then nothing will - # happen, otherwise there are two possible exceptions that can be raised: - # - # - NoMethodError: the targeted resource does not handle the scope that - # is being checked. It will raise a ScopeNotHandled. - # - Pundit::NotAuthorizedError: the targeted resource unauthorized the - # given user for the scope that is being checked. In this case this - # scope gets removed from `auth_scope.actions`. - begin - authorize auth_scope.resource, "#{action}?".to_sym - rescue NoMethodError, Pundit::NotAuthorizedError, Portus::AuthScope::ResourceNotFound - logger.debug "action #{action} not handled/authorized, removing from actions" - auth_scope.actions.delete_if { |a| match_action(action, a) } - end - end - + actions.each { |action| triage_action!(auth_scope, action) } next if auth_scope.actions.empty? - # if there is already a similar scope (type and resource name), - # we combine them into one: + + # If there is already a similar scope (type and resource name), we combine + # them into one: # e.g. scope=repository:busybox:push&scope=repository:busybox:pull # -> access=>[{:type=>"repository", :name=>"busybox", :actions=>["push", "pull"]} k = [auth_scope.resource_type, auth_scope.resource_name] @@ -82,6 +68,22 @@ def authorize_scopes(registry) auth_scopes.values end + # It will try to check if the current user is authorized to access the + # scope given in this iteration. If everything is fine, then nothing will + # happen, otherwise there are two possible exceptions that can be raised: + # + # - NoMethodError: the targeted resource does not handle the scope that + # is being checked. It will raise a ScopeNotHandled. + # - Pundit::NotAuthorizedError: the targeted resource unauthorized the + # given user for the scope that is being checked. In this case this + # scope gets removed from `auth_scope.actions`. + def triage_action!(auth_scope, action) + authorize auth_scope.resource, "#{action}?".to_sym + rescue NoMethodError, Pundit::NotAuthorizedError, Portus::AuthScope::ResourceNotFound + logger.debug "action #{action} not handled/authorized, removing from actions" + auth_scope.actions.delete_if { |a| match_action(action, a) } + end + # Returns true if the given item matches the given action. def match_action(action, item) action = "*" if action == "all" diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 83b0111f4..c09200f89 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/auth_from_token" class ApplicationController < ActionController::Base diff --git a/app/controllers/application_tokens_controller.rb b/app/controllers/application_tokens_controller.rb index 028032240..2cd157403 100644 --- a/app/controllers/application_tokens_controller.rb +++ b/app/controllers/application_tokens_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # ApplicationTokensController manages the creation/removal of application tokens class ApplicationTokensController < ApplicationController respond_to :js diff --git a/app/controllers/auth/omniauth_callbacks_controller.rb b/app/controllers/auth/omniauth_callbacks_controller.rb index e0b68555f..86b4ff315 100644 --- a/app/controllers/auth/omniauth_callbacks_controller.rb +++ b/app/controllers/auth/omniauth_callbacks_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController skip_before_action :verify_authenticity_token before_action :check_user, except: [:failure] @@ -49,7 +51,7 @@ def check_domain true else redirect_to new_user_session_url, - alert: "Email addresses on the domain #{d} aren't allowed." + alert: "Email addresses on the domain #{d} aren't allowed." false end end diff --git a/app/controllers/auth/omniauth_registrations_controller.rb b/app/controllers/auth/omniauth_registrations_controller.rb index 06d782814..8e5575a8d 100644 --- a/app/controllers/auth/omniauth_registrations_controller.rb +++ b/app/controllers/auth/omniauth_registrations_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Auth::OmniauthRegistrationsController < ApplicationController layout "authentication" skip_before_action :authenticate_user! diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 07c99a2b8..bbde83114 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + class Auth::RegistrationsController < Devise::RegistrationsController layout "authentication", except: :edit include CheckLDAP include SessionFlash - before_action :check_signup, only: [:new, :create] - before_action :check_admin, only: [:new, :create] + before_action :check_signup, only: %i[new create] + before_action :check_admin, only: %i[new create] before_action :configure_sign_up_params, only: [:create] before_action :authenticate_user!, only: [:disable] @@ -26,7 +28,7 @@ def create respond_with resource, location: after_sign_up_path_for(resource), float: true else redirect_to new_user_registration_path, - alert: resource.errors.full_messages + alert: resource.errors.full_messages end end @@ -47,10 +49,10 @@ def update if success redirect_to edit_user_registration_path, - notice: "Profile updated successfully!", float: true + notice: "Profile updated successfully!", float: true else redirect_to edit_user_registration_path, - alert: resource.errors.full_messages, float: true + alert: resource.errors.full_messages, float: true end end diff --git a/app/controllers/auth/sessions_controller.rb b/app/controllers/auth/sessions_controller.rb index 316581219..30c912c1d 100644 --- a/app/controllers/auth/sessions_controller.rb +++ b/app/controllers/auth/sessions_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Auth::SessionsController < Devise::SessionsController include SessionFlash diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 87b613f05..612502579 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CommentsController < ApplicationController before_action :set_repository respond_to :js, :html diff --git a/app/controllers/concerns/change_name_description.rb b/app/controllers/concerns/change_name_description.rb index 8061b3f07..50f5c8915 100644 --- a/app/controllers/concerns/change_name_description.rb +++ b/app/controllers/concerns/change_name_description.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ChangeNameDescription extend ActiveSupport::Concern @@ -19,15 +21,15 @@ def change_name_description(object, symbol, params, activity_params = {}) # Create a PublicActivity for updating an attribute. def create_activity(object, symbol, old_value, new_value, activity_params) object.create_activity "change_#{symbol}".to_sym, - owner: current_user, - recipient: object, - parameters: activity_params.merge(old: old_value, new: new_value) + owner: current_user, + recipient: object, + parameters: activity_params.merge(old: old_value, new: new_value) end # Change description and track activity if successful. def change_description(object, symbol, old_description, new_description, activity_params) return if new_description.nil? || old_description == new_description || - !object.update(description: new_description) + !object.update(description: new_description) create_activity(object, "#{symbol}_description", old_description, new_description, activity_params) end diff --git a/app/controllers/concerns/check_ldap.rb b/app/controllers/concerns/check_ldap.rb index fe730b105..c8554bcf4 100644 --- a/app/controllers/concerns/check_ldap.rb +++ b/app/controllers/concerns/check_ldap.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # CheckLDAP redirects the user to the new_user_session_path if LDAP support is # enabled. A `before_action` will be created for the :new and the :create # methods. @@ -5,7 +7,7 @@ module CheckLDAP extend ActiveSupport::Concern included do - before_action :check_ldap, only: [:new, :create] + before_action :check_ldap, only: %i[new create] end # Redirect to the login page if LDAP is enabled. diff --git a/app/controllers/concerns/deletable.rb b/app/controllers/concerns/deletable.rb index 3fade3543..c35d5690f 100644 --- a/app/controllers/concerns/deletable.rb +++ b/app/controllers/concerns/deletable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Deletable redirects the user back if delete support is not enabled. A # `before_action` will be created for the :destroy method. module Deletable diff --git a/app/controllers/concerns/headers.rb b/app/controllers/concerns/headers.rb index 0f63ea6fb..25427aa2d 100644 --- a/app/controllers/concerns/headers.rb +++ b/app/controllers/concerns/headers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Concern which has methods dealing with headers that might be interesting for # controllers deriving directly from ActionController::Base. module Headers diff --git a/app/controllers/concerns/session_flash.rb b/app/controllers/concerns/session_flash.rb index 6f4204eac..3de0b0d2f 100644 --- a/app/controllers/concerns/session_flash.rb +++ b/app/controllers/concerns/session_flash.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # SessionFlash adds the `session_flash` method which deals with flashy messages # on signup/login, while notifying users about their personal namespace. module SessionFlash @@ -24,10 +26,11 @@ def session_flash(user, method) ns = user.namespace.name str = " Your personal namespace is '#{ns}'" str += if user.username == ns - "." - else - " (your username was not a valid Docker namespace, so we had to tweak it)." - end - flash[:notice] << str + "." + else + " (your username was not a valid Docker namespace, " \ + "so we had to tweak it)." + end + flash[:notice] += str end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 82b460d9d..2c24e4ac2 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class DashboardController < ApplicationController def index @recent_activities = policy_scope(PublicActivity::Activity) diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb index abd2c7d68..6bad7ff71 100644 --- a/app/controllers/errors_controller.rb +++ b/app/controllers/errors_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # We use our own error routes because we need to display pages for bad server # configurations too. Moreover, this way we get richer pages while sharing as # much code as possible. diff --git a/app/controllers/explore_controller.rb b/app/controllers/explore_controller.rb index c964fe54c..48024dce8 100644 --- a/app/controllers/explore_controller.rb +++ b/app/controllers/explore_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # ExploreController exposes a search interface for non-logged in (anonymous) # users. It allows these users to search for public repositories. class ExploreController < ActionController::Base diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 8706f4846..2888eb8ba 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # HelpController holds the methods for rendering the help pages inside of Portus. class HelpController < ApplicationController # Main help page. diff --git a/app/controllers/namespaces_controller.rb b/app/controllers/namespaces_controller.rb index 764b984c5..cc4223962 100644 --- a/app/controllers/namespaces_controller.rb +++ b/app/controllers/namespaces_controller.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class NamespacesController < ApplicationController include ChangeNameDescription - before_action :set_namespace, only: [:change_visibility, :show, :update] + before_action :set_namespace, only: %i[change_visibility show update] - after_action :verify_authorized, except: [:index, :typeahead] + after_action :verify_authorized, except: %i[index typeahead] after_action :verify_policy_scoped, only: :index # GET /namespaces @@ -73,8 +75,8 @@ def change_visibility return unless @namespace.update_attributes(visibility: visibility_param) @namespace.create_activity :change_visibility, - owner: current_user, - parameters: { visibility: @namespace.visibility } + owner: current_user, + parameters: { visibility: @namespace.visibility } respond_to do |format| format.js { render :change_visibility } @@ -94,8 +96,8 @@ def change_team(p) @namespace.errors[:team_id] << "'#{p[:team]}' unknown." else @namespace.create_activity :change_team, - owner: current_user, - parameters: { old: @namespace.team.id, new: @team.id } + owner: current_user, + parameters: { old: @namespace.team.id, new: @team.id } @namespace.update_attributes(team: @team) end end diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index 6d6434f0b..a3d65620c 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # PasswordsController is a Devise controller that takes care of the "password # forgotten" mechanism. class PasswordsController < Devise::PasswordsController @@ -27,7 +29,7 @@ def update else token = params[:user][:reset_password_token] redirect_to "/users/password/edit?reset_password_token=#{token}", - alert: resource.errors.full_messages, float: true + alert: resource.errors.full_messages, float: true end end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index f8187326e..e8c2c9c76 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class RepositoriesController < ApplicationController include Deletable - before_action :set_repository, only: [:show, :destroy, :toggle_star] + before_action :set_repository, only: %i[show destroy toggle_star] # GET /repositories # GET /repositories.json @@ -50,7 +52,7 @@ def destroy else @repository.delete_and_update!(current_user) redirect_to namespace_path(@repository.namespace), - notice: "Repository removed with all its tags", float: true + notice: "Repository removed with all its tags", float: true end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 51cef0990..6adf4f9fc 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SearchController < ApplicationController def index search = params[:search].split(":").first diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index bbee07b45..ec4976267 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TagsController < ApplicationController include Deletable diff --git a/app/controllers/team_users_controller.rb b/app/controllers/team_users_controller.rb index 598ab80ff..3cb51dd44 100644 --- a/app/controllers/team_users_controller.rb +++ b/app/controllers/team_users_controller.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + # TeamUsersController manages the creation/removal/update of members of a team. class TeamUsersController < ApplicationController before_action :set_team_user - before_action :promoted_owner, only: [:create, :update] - before_action :only_owner, only: [:update, :destroy] + before_action :promoted_owner, only: %i[create update] + before_action :only_owner, only: %i[update destroy] after_action :verify_authorized respond_to :js diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 1b46bdbed..aaf5b0c43 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + class TeamsController < ApplicationController include ChangeNameDescription - before_action :set_team, only: [:show, :update, :typeahead] + before_action :set_team, only: %i[show update typeahead] after_action :verify_policy_scoped, only: :index respond_to :js, :html diff --git a/app/controllers/webhook_deliveries_controller.rb b/app/controllers/webhook_deliveries_controller.rb index e618946da..2aa3dd9de 100644 --- a/app/controllers/webhook_deliveries_controller.rb +++ b/app/controllers/webhook_deliveries_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # WebhookDeliveriesController manages the updates of webhook deliveries. class WebhookDeliveriesController < ApplicationController respond_to :html, :js diff --git a/app/controllers/webhook_headers_controller.rb b/app/controllers/webhook_headers_controller.rb index 8e2b34a26..d1f2f7a5e 100644 --- a/app/controllers/webhook_headers_controller.rb +++ b/app/controllers/webhook_headers_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # WebhookHeadersController manages the creation/removal of webhook headers. class WebhookHeadersController < ApplicationController respond_to :html, :js diff --git a/app/controllers/webhooks_controller.rb b/app/controllers/webhooks_controller.rb index f6e70c101..66fe6f6d9 100644 --- a/app/controllers/webhooks_controller.rb +++ b/app/controllers/webhooks_controller.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + # WebhooksController manages the creation/removal/update of webhooks. # Also, it manages their state, i.e. enabled/disabled. class WebhooksController < ApplicationController respond_to :html, :js before_action :set_namespace - before_action :set_webhook, only: [:update, :show, :destroy, :toggle_enabled] + before_action :set_webhook, only: %i[update show destroy toggle_enabled] after_action :verify_authorized, except: [:index] after_action :verify_policy_scoped, only: :index diff --git a/app/helpers/activities_helper.rb b/app/helpers/activities_helper.rb index 8977ff891..c51312572 100644 --- a/app/helpers/activities_helper.rb +++ b/app/helpers/activities_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Common methods for activities used in other helpers. module ActivitiesHelper # Returns a string containing the username of the owner of the activity. diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bb12241af..78febc953 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationHelper include ActivitiesHelper @@ -59,8 +61,6 @@ def markdown(text) renderer = Redcarpet::Render::HTML.new(render_options) m = Redcarpet::Markdown.new(renderer, extensions) - # rubocop:disable Rails/OutputSafety - m.render(text).html_safe - # rubocop:enable Rails/OutputSafety + sanitize(m.render(text)) end end diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb index 960cb6ec3..f262f4a20 100644 --- a/app/helpers/comments_helper.rb +++ b/app/helpers/comments_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CommentsHelper # Return true if current_user has permission to destroy a comment # Returns false otherwise diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb index 0e37caf74..88015ba8e 100644 --- a/app/helpers/namespaces_helper.rb +++ b/app/helpers/namespaces_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module NamespacesHelper def can_manage_namespace?(namespace) current_user.admin? || (owner?(namespace) && diff --git a/app/helpers/registries_helper.rb b/app/helpers/registries_helper.rb index 29948349d..9b0e3dbd0 100644 --- a/app/helpers/registries_helper.rb +++ b/app/helpers/registries_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module RegistriesHelper # Render registry status icon def registry_status_icon(registry) @@ -5,7 +7,7 @@ def registry_status_icon(registry) msg = error.empty? ? "Reachable" : error time = Time.now.getlocal.to_s(:rfc822) icon = "chain" - icon << "-broken" unless error.empty? + icon += "-broken" unless error.empty? title = "#{msg} - Checked at #{time}" diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 598372b91..d5e9fabae 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Rendering push activities can be tricky, since tags can come on go, and with # them, dangling repositories that used to contain them. Because of this, this # helper renders the proper HTML for push activities, while being safe at it. @@ -35,6 +37,18 @@ def can_destroy?(repository) RepositoryPolicy.new(current_user, repository).destroy? end + # Returns if any security module is enabled + def security_vulns_enabled? + ::Portus::Security.enabled? + end + + # Returns true if any vulnerability is found + # Or false otherwise + def vulnerable?(vulnerabilities) + return if vulnerabilities.blank? + !vulnerabilities.reject { |_, vulns| vulns.empty? }.empty? + end + protected # General method for rendering an activity regarding repositories. @@ -128,16 +142,4 @@ def repo_name(activity) def name_and_link(tr, activity) tr.is_a?(Namespace) ? [repo_name(activity), nil] : [tr.name, tr] end - - # Returns if any security module is enabled - def security_vulns_enabled? - ::Portus::Security.enabled? - end - - # Returns true if any vulnerability is found - # Or false otherwise - def vulnerable?(vulnerabilities) - return if vulnerabilities.blank? - !vulnerabilities.reject { |_, vulns| vulns.empty? }.empty? - end end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 141b81960..f7221bda1 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module SearchHelper def build_search_category_url(params, category) "#{search_index_path}?utf8=#{params[:utf8]}&search=#{params[:search]}&type=#{category}" diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb index 4a75bab60..e88e11045 100644 --- a/app/helpers/sessions_helper.rb +++ b/app/helpers/sessions_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # # Renders the social login buttons if one of the `oauth` configuration has been enabled. # diff --git a/app/helpers/teams_helper.rb b/app/helpers/teams_helper.rb index ec1ddc694..0eaec4a9a 100644 --- a/app/helpers/teams_helper.rb +++ b/app/helpers/teams_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TeamsHelper def can_manage_team?(team) current_user.admin? || (team.owners.exists?(current_user.id) && diff --git a/app/jobs/catalog_job.rb b/app/jobs/catalog_job.rb index f8a5e28ea..7f5d71303 100644 --- a/app/jobs/catalog_job.rb +++ b/app/jobs/catalog_job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # CatalogJob is a job that synchronizes the contents of the database with the # contents of the registries. This is done by using the Catalog API. class CatalogJob < ActiveJob::Base @@ -14,6 +16,7 @@ def perform # the DB in an unknown state because of an update failure. ActiveRecord::Base.transaction { update_registry!(cat) } rescue StandardError => e + # TODO: let's not rescue everything Rails.logger.warn "Exception: #{e.message}" end end diff --git a/app/mailers/devise_mailer.rb b/app/mailers/devise_mailer.rb index a332697e6..0e30cade3 100644 --- a/app/mailers/devise_mailer.rb +++ b/app/mailers/devise_mailer.rb @@ -1,3 +1,6 @@ +# frozen_string_literal: true + +# DeviseMailer is the mailer being used by Devise. class DeviseMailer < Devise::Mailer default from: "#{APP_CONFIG["email"]["name"]} <#{APP_CONFIG["email"]["from"]}>" default reply_to: APP_CONFIG["email"]["reply_to"] diff --git a/app/middleware/catch_json_parse_errors.rb b/app/middleware/catch_json_parse_errors.rb index b7a321c4d..0be0df108 100644 --- a/app/middleware/catch_json_parse_errors.rb +++ b/app/middleware/catch_json_parse_errors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # The class intercepts ActionDispatch::ParamsParser::ParseError if request # accept application/json. class CatchJsonParseErrors @@ -8,7 +10,7 @@ def initialize(app) def call(env) @app.call(env) rescue ActionDispatch::ParamsParser::ParseError => error - raise error unless env["HTTP_ACCEPT"].match?(/application\/json/) + raise error unless env["HTTP_ACCEPT"].match?(%r{application/json}) error_output = "There was a problem in the JSON you submitted: #{error}" [ 400, { "Content-Type" => "application/json" }, diff --git a/app/models/application_token.rb b/app/models/application_token.rb index 1a119cf9b..084701cc1 100644 --- a/app/models/application_token.rb +++ b/app/models/application_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: application_tokens diff --git a/app/models/comment.rb b/app/models/comment.rb index 94722a464..51ba46690 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: comments diff --git a/app/models/namespace.rb b/app/models/namespace.rb index aad8095fe..209c26a00 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: namespaces @@ -43,7 +45,7 @@ class Namespace < ActiveRecord::Base belongs_to :registry belongs_to :team - enum visibility: [:visibility_private, :visibility_protected, :visibility_public] + enum visibility: %i[visibility_private visibility_protected visibility_public] validate :global_namespace_cannot_be_private validates :name, @@ -79,16 +81,16 @@ def self.get_from_name(name, registry = nil) if name.include?("/") namespace, name = name.split("/", 2) namespace = if registry.nil? - Namespace.find_by(name: namespace) - else - registry.namespaces.find_by(name: namespace) - end + Namespace.find_by(name: namespace) + else + registry.namespaces.find_by(name: namespace) + end else namespace = if registry.nil? - Namespace.find_by(global: true) - else - Namespace.find_by(registry: registry, global: true) - end + Namespace.find_by(global: true) + else + Namespace.find_by(registry: registry, global: true) + end end [namespace, name, registry] end diff --git a/app/models/namespace/auth_scope.rb b/app/models/namespace/auth_scope.rb index 4737f4ac0..3de3b00c7 100644 --- a/app/models/namespace/auth_scope.rb +++ b/app/models/namespace/auth_scope.rb @@ -1,13 +1,15 @@ +# frozen_string_literal: true + # Namespace::AuthScope parses the scope string for the "namespace" type. class Namespace::AuthScope < Portus::AuthScope attr_accessor :actions, :resource_type, :resource_name def resource found_resource = if @namespace_name.blank? - @registry.namespaces.find_by(global: true) - else - @registry.namespaces.find_by(name: @namespace_name) - end + @registry.namespaces.find_by(global: true) + else + @registry.namespaces.find_by(name: @namespace_name) + end raise ResourceNotFound, "Cannot find namespace #{@namespace_name}" if found_resource.nil? diff --git a/app/models/registry.rb b/app/models/registry.rb index e4d7e3212..197c1bb46 100644 --- a/app/models/registry.rb +++ b/app/models/registry.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: registries @@ -111,37 +113,14 @@ def get_namespace_from_event(event, fetch_tag = true) # is returned. Otherwise a string will be returned containing the reasoning # of the reachability failure. def reachable? - msg = "" - - # rubocop:disable Lint/ShadowedException: - begin - r = client.reachable? - - # At this point, !r is only possible if the returned code is 404, which - # according to the documentation we have to assume that the registry is - # not implementing the v2 of the API. - return "Error: registry does not implement v2 of the API." unless r - rescue Errno::ECONNREFUSED, SocketError - msg = "Error: connection refused. The given registry is not available!" - rescue Errno::ETIMEDOUT, Net::OpenTimeout - msg = "Error: connection timed out. The given registry is not available!" - rescue Net::HTTPBadResponse - msg = if use_ssl - "Error: there's something wrong with your SSL configuration." - else - "Error: not using SSL, but the given registry does use SSL." - end - rescue OpenSSL::SSL::SSLError => e - msg = "SSL error while communicating with the registry, check the server " \ - "logs for more details." - logger.error(e) - rescue StandardError => e - # We don't know what went wrong :/ - logger.info "Registry not reachable: #{e.inspect}" - msg = "Error: something went wrong. Check your configuration." - end - # rubocop:enable Lint/ShadowedException: - msg + r = client.reachable? + + # All possible errors are already handled by the `reachable` method through + # the `::Portus::Request` exception. If we are still facing an issue, the + # assumption is that the given registry does not implement v2. + r ? "" : "Error: registry does not implement v2 of the API." + rescue ::Portus::RequestError => e + e.message end protected diff --git a/app/models/registry/auth_scope.rb b/app/models/registry/auth_scope.rb index db7fe7899..de8e52b81 100644 --- a/app/models/registry/auth_scope.rb +++ b/app/models/registry/auth_scope.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Registry::AuthScope parses the scope string so it can be used afterwards for # the "registry" type. class Registry::AuthScope < Portus::AuthScope diff --git a/app/models/registry_event.rb b/app/models/registry_event.rb index 4a403c425..843422096 100644 --- a/app/models/registry_event.rb +++ b/app/models/registry_event.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: registry_events diff --git a/app/models/repository.rb b/app/models/repository.rb index af3a5cb7d..db67f7751 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: repositories @@ -99,9 +101,7 @@ def self.handle_push_event(event) repository = Repository.add_repo(event, namespace, repo_name, tag_name) return if repository.nil? - # rubocop:disable Style/SafeNavigation - namespace.repositories << repository if namespace - # rubocop:enable Style/SafeNavigation + namespace&.repositories&.push(repository) repository end @@ -237,14 +237,13 @@ def self.create_tags(client, repository, author, tags) tags.each do |tag| # Try to fetch the manifest digest of the tag. - # rubocop:disable Lint/RescueWithoutErrorClass begin id, digest, = client.manifest(repository.full_name, tag) - rescue + rescue ::Portus::RegistryClient::ManifestError, ::Portus::RequestError => e + Rails.logger.info e.to_s id = "" digest = "" end - # rubocop:enable Lint/RescueWithoutErrorClass t = Tag.create!( name: tag, diff --git a/app/models/star.rb b/app/models/star.rb index 667177276..abf89fc6b 100644 --- a/app/models/star.rb +++ b/app/models/star.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: stars diff --git a/app/models/tag.rb b/app/models/tag.rb index 36c5d5309..0871021ed 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: tags diff --git a/app/models/team.rb b/app/models/team.rb index b7c627c87..17fb5e3fb 100644 --- a/app/models/team.rb +++ b/app/models/team.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: teams @@ -36,11 +38,11 @@ class Team < ActiveRecord::Base has_many :team_users, dependent: :destroy has_many :users, through: :team_users has_many :owners, -> { merge TeamUser.owner }, - through: :team_users, source: :user + through: :team_users, source: :user has_many :contributors, -> { merge TeamUser.contributor }, - through: :team_users, source: :user + through: :team_users, source: :user has_many :viewers, -> { merge TeamUser.viewer }, - through: :team_users, source: :user + through: :team_users, source: :user # Returns all the member-IDs def member_ids diff --git a/app/models/team_user.rb b/app/models/team_user.rb index 450d8877c..b1912ff1a 100644 --- a/app/models/team_user.rb +++ b/app/models/team_user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: team_users @@ -22,7 +24,7 @@ # * contributor: has RW access to the namespaces associated with the team # * owner: like contributor, but can also manage the team class TeamUser < ActiveRecord::Base - enum role: [:viewer, :contributor, :owner] + enum role: %i[viewer contributor owner] scope :enabled, -> { joins(:user).merge(User.enabled).distinct } scope :owner, -> { where(role: roles[:owner]) } diff --git a/app/models/user.rb b/app/models/user.rb index 1c30bc4a8..fe200fc11 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: users @@ -41,12 +43,12 @@ class User < ActiveRecord::Base enabled_devise_modules = [:database_authenticatable, :registerable, :lockable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable, - omniauth_providers: [ - :google_oauth2, - :open_id, - :github, - :gitlab, - :bitbucket + omniauth_providers: %i[ + google_oauth2 + open_id + github + gitlab + bitbucket ], authentication_keys: [:username]] diff --git a/app/models/webhook.rb b/app/models/webhook.rb index c934c5f51..614b21a9a 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhooks @@ -34,7 +36,7 @@ class Webhook < ActiveRecord::Base include PublicActivity::Common - enum request_method: ["GET", "POST"] + enum request_method: %w[GET POST] enum content_type: ["application/json", "application/x-www-form-urlencoded"] belongs_to :namespace diff --git a/app/models/webhook_delivery.rb b/app/models/webhook_delivery.rb index fcc5232f1..3df515c64 100644 --- a/app/models/webhook_delivery.rb +++ b/app/models/webhook_delivery.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_deliveries diff --git a/app/models/webhook_header.rb b/app/models/webhook_header.rb index 497d78973..f69b5fd2f 100644 --- a/app/models/webhook_header.rb +++ b/app/models/webhook_header.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_headers diff --git a/app/policies/comment_policy.rb b/app/policies/comment_policy.rb index 0ea4dfdb1..496ec88e8 100644 --- a/app/policies/comment_policy.rb +++ b/app/policies/comment_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CommentPolicy attr_reader :user, :comment diff --git a/app/policies/namespace_policy.rb b/app/policies/namespace_policy.rb index 01f0e6f20..521ec5a2a 100644 --- a/app/policies/namespace_policy.rb +++ b/app/policies/namespace_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NamespacePolicy attr_reader :user, :namespace diff --git a/app/policies/public_activity/activity_policy.rb b/app/policies/public_activity/activity_policy.rb index fb3aed1e2..54656e56d 100644 --- a/app/policies/public_activity/activity_policy.rb +++ b/app/policies/public_activity/activity_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class PublicActivity::ActivityPolicy class Scope attr_reader :user, :scope @@ -11,57 +13,70 @@ def resolve(count = 20) teams_ids = @user.teams.collect(&:id) public_visibility = Namespace.visibilities[:visibility_public] - # Show Team events only if user is a member of the team - team_activities = @scope - .where("activities.trackable_type = ? AND activities.trackable_id IN (?)", - "Team", teams_ids) - .order(id: :desc) - .limit(count) + team_activities(teams_ids, count) + .union_all(namespace_activities(teams_ids, public_visibility, count)) + .union_all(repository_activities(teams_ids, public_visibility, count)) + .union_all(application_token_activities(count)) + .union_all(webhook_activities(count)) + .distinct + end - # Show Namespace events only if user is a member of the team controlling - # the namespace or if the event is a public <-> private switch. - namespace_activities = @scope - .joins("INNER JOIN namespaces " \ - "ON activities.trackable_id = namespaces.id") - .where("activities.trackable_type = ? AND " \ - "(namespaces.team_id IN (?) OR " \ - "(activities.key = ? AND namespaces.visibility = ?))", - "Namespace", teams_ids, "namespace.change_visibility", - public_visibility) - .order(id: :desc) - .limit(count) + protected - # Show tag events for repositories inside of namespaces controller by - # a team the user is part of, or tags part of public namespaces. - repository_activities = @scope - .joins("INNER JOIN repositories " \ - "ON activities.trackable_id = repositories.id " \ - "INNER JOIN namespaces " \ - "ON namespaces.id = repositories.namespace_id") - .where("activities.trackable_type = ? AND " \ - "(namespaces.team_id IN (?) OR namespaces.visibility = ?)", - "Repository", teams_ids, public_visibility) - .order(id: :desc) - .limit(count) + # Show Team events only if user is a member of the team + def team_activities(teams_ids, count) + @scope + .where("activities.trackable_type = ? AND activities.trackable_id IN (?)", + "Team", teams_ids) + .order(id: :desc) + .limit(count) + end + + # Show Namespace events only if user is a member of the team controlling + # the namespace or if the event is a public <-> private switch. + def namespace_activities(teams_ids, public_visibility, count) + @scope + .joins("INNER JOIN namespaces " \ + "ON activities.trackable_id = namespaces.id") + .where("activities.trackable_type = ? AND " \ + "(namespaces.team_id IN (?) OR " \ + "(activities.key = ? AND namespaces.visibility = ?))", + "Namespace", teams_ids, "namespace.change_visibility", + public_visibility) + .order(id: :desc) + .limit(count) + end - # Show application tokens activities related only to the current user - application_token_activities = @scope - .where("activities.trackable_type = ? " \ - "AND activities.owner_id = ?", - "ApplicationToken", user.id) - .order(id: :desc) - .limit(count) + # Show tag events for repositories inside of namespaces controller by + # a team the user is part of, or tags part of public namespaces. + def repository_activities(teams_ids, public_visibility, count) + @scope + .joins("INNER JOIN repositories " \ + "ON activities.trackable_id = repositories.id " \ + "INNER JOIN namespaces " \ + "ON namespaces.id = repositories.namespace_id") + .where("activities.trackable_type = ? AND " \ + "(namespaces.team_id IN (?) OR namespaces.visibility = ?)", + "Repository", teams_ids, public_visibility) + .order(id: :desc) + .limit(count) + end - team_activities - .union_all(namespace_activities) - .union_all(repository_activities) - .union_all(application_token_activities) - .union_all(webhook_activities(count)) - .distinct + # Show application tokens activities related only to the current user + def application_token_activities(count) + @scope + .where("activities.trackable_type = ? " \ + "AND activities.owner_id = ?", + "ApplicationToken", @user.id) + .order(id: :desc) + .limit(count) end # webhook_activities returns all webhook activities which are accessibly to # the user. + # NOTE: this method is potentially quite expensive. I'm sure it can be + # optimized. + # rubocop:disable Metrics/MethodLength def webhook_activities(count) # Show webhook events only if user is a member of the team controlling # the namespace. @@ -104,5 +119,6 @@ def webhook_activities(count) # "convert" array back to relation in order to use `union_all`. @scope.where(id: activities.map(&:id)) end + # rubocop:enable Metrics/MethodLength end end diff --git a/app/policies/registry_policy.rb b/app/policies/registry_policy.rb index 1f865076d..176b00878 100644 --- a/app/policies/registry_policy.rb +++ b/app/policies/registry_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # RegistryPolicy implements the authorization policy for methods inside the # "registry" type. class RegistryPolicy diff --git a/app/policies/repository_policy.rb b/app/policies/repository_policy.rb index 42c1e3412..c389b1f4f 100644 --- a/app/policies/repository_policy.rb +++ b/app/policies/repository_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RepositoryPolicy attr_reader :user, :repository @@ -34,7 +36,7 @@ def resolve @scope .joins(namespace: { team: :users }) .where("namespaces.visibility = :namespace_visibility", - namespace_visibility: Namespace.visibilities[:visibility_public]) + namespace_visibility: Namespace.visibilities[:visibility_public]) .distinct elsif user.admin? @scope.all @@ -45,8 +47,8 @@ def resolve .joins(namespace: { team: :users }) .where("namespaces.visibility = :namespace_visibility OR " \ "users.id = :user_id", - namespace_visibility: Namespace.visibilities[:visibility_public], - user_id: @user.id) + namespace_visibility: Namespace.visibilities[:visibility_public], + user_id: @user.id) .distinct end end diff --git a/app/policies/tag_policy.rb b/app/policies/tag_policy.rb index 33bd0f5ad..27a0e00b8 100644 --- a/app/policies/tag_policy.rb +++ b/app/policies/tag_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Defines the policy for the tag object. class TagPolicy attr_reader :user, :tag diff --git a/app/policies/team_policy.rb b/app/policies/team_policy.rb index d8c40822e..0f341da48 100644 --- a/app/policies/team_policy.rb +++ b/app/policies/team_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class TeamPolicy attr_reader :user, :team diff --git a/app/policies/team_user_policy.rb b/app/policies/team_user_policy.rb index 2606cb77f..315227a68 100644 --- a/app/policies/team_user_policy.rb +++ b/app/policies/team_user_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Policy for team members. It does not authorize anything unless the author of # the action is an owner. An owner is either an admin of Portus or an owner of # the team itself. diff --git a/app/policies/webhook_delivery_policy.rb b/app/policies/webhook_delivery_policy.rb index 917a4f86e..a6352eb13 100644 --- a/app/policies/webhook_delivery_policy.rb +++ b/app/policies/webhook_delivery_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WebhookDeliveryPolicy < WebhookPolicy attr_reader :webhook_delivery diff --git a/app/policies/webhook_header_policy.rb b/app/policies/webhook_header_policy.rb index 87b6bfa9d..d49f39f08 100644 --- a/app/policies/webhook_header_policy.rb +++ b/app/policies/webhook_header_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WebhookHeaderPolicy < WebhookPolicy attr_reader :webhook_header diff --git a/app/policies/webhook_policy.rb b/app/policies/webhook_policy.rb index 055acdec1..04b9b62b7 100644 --- a/app/policies/webhook_policy.rb +++ b/app/policies/webhook_policy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class WebhookPolicy < NamespacePolicy attr_reader :webhook @@ -44,9 +46,9 @@ def resolve .where( "(namespaces.visibility = :public OR namespaces.visibility = :protected OR "\ "team_users.user_id = :user_id) AND namespaces.global = :global", - public: Namespace.visibilities[:visibility_public], - protected: Namespace.visibilities[:visibility_protected], user_id: user.id, - global: false + public: Namespace.visibilities[:visibility_public], + protected: Namespace.visibilities[:visibility_protected], user_id: user.id, + global: false ) .pluck(:id) diff --git a/app/services/README.md b/app/services/README.md new file mode 100644 index 000000000..68076bcb8 --- /dev/null +++ b/app/services/README.md @@ -0,0 +1,6 @@ +## Services + +This directory contains services. A service is simply a piece of code that is +shared between the Grape API and the controllers. Each action has been +implemented as a different service, which can then be executed independently of +the context. diff --git a/app/services/base_service.rb b/app/services/base_service.rb index 6a1674d2f..51db00b0c 100644 --- a/app/services/base_service.rb +++ b/app/services/base_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BaseService attr_accessor :current_user, :params diff --git a/app/services/base_validate_service.rb b/app/services/base_validate_service.rb index cdbdf5d51..ca140b6ba 100644 --- a/app/services/base_validate_service.rb +++ b/app/services/base_validate_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BaseValidateService attr_accessor :params diff --git a/app/services/namespaces/build_service.rb b/app/services/namespaces/build_service.rb index ed7dfae75..eb921ef42 100644 --- a/app/services/namespaces/build_service.rb +++ b/app/services/namespaces/build_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Namespaces class BuildService < ::BaseService def execute diff --git a/app/services/namespaces/create_service.rb b/app/services/namespaces/create_service.rb index c774aa1f1..aff4e16c8 100644 --- a/app/services/namespaces/create_service.rb +++ b/app/services/namespaces/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Namespaces class CreateService < ::BaseService attr_accessor :namespace diff --git a/app/services/registries/validate_service.rb b/app/services/registries/validate_service.rb index 97d938993..32dc1dc15 100644 --- a/app/services/registries/validate_service.rb +++ b/app/services/registries/validate_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Registries class ValidateService < ::BaseValidateService def execute diff --git a/app/services/teams/create_service.rb b/app/services/teams/create_service.rb index 4d860a658..c82419ceb 100644 --- a/app/services/teams/create_service.rb +++ b/app/services/teams/create_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Teams class CreateService < ::BaseService def execute diff --git a/app/validators/namespace_validator.rb b/app/validators/namespace_validator.rb index f5ff48846..0d4cbd979 100644 --- a/app/validators/namespace_validator.rb +++ b/app/validators/namespace_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Validates the name of the namespace as specified by Docker Distribution. class NamespaceValidator < ActiveModel::EachValidator NAME_REGEXP = /\A[a-z0-9]+(?:[._\\-][a-z0-9]+)*\Z/ diff --git a/app/validators/unique_tag_validator.rb b/app/validators/unique_tag_validator.rb index 3c6c69c52..2a3b792cd 100644 --- a/app/validators/unique_tag_validator.rb +++ b/app/validators/unique_tag_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/db" # See https://github.com/SUSE/Portus/pull/1494 on why we didn't use the diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb index ccfe6695a..c39fe1013 100644 --- a/app/validators/url_validator.rb +++ b/app/validators/url_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "uri" # Validates URLs diff --git a/bin/background.rb b/bin/background.rb index 00be10a5b..50b29873c 100644 --- a/bin/background.rb +++ b/bin/background.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/db" # diff --git a/bin/bundle b/bin/bundle index fe1874509..277e12825 100755 --- a/bin/bundle +++ b/bin/bundle @@ -1,3 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) load Gem.bin_path("bundler", "bundle") diff --git a/bin/check_db.rb b/bin/check_db.rb index 84a9a543d..f1b407aa1 100644 --- a/bin/check_db.rb +++ b/bin/check_db.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This is a rails runner that will print the status of Portus' database. # Possible outcomes: # @@ -23,4 +25,4 @@ "DB_DOWN" else "DB_UNKNOWN" -end + end diff --git a/bin/client.rb b/bin/client.rb index dc6afb15e..926de5f5d 100644 --- a/bin/client.rb +++ b/bin/client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This script has to be used inside of the `rails runner` command. So, for # example, to get the results from the manifest: # diff --git a/bin/generate_test_data.rb b/bin/generate_test_data.rb index 5efd36c13..267b0a166 100644 --- a/bin/generate_test_data.rb +++ b/bin/generate_test_data.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" require "pty" @@ -8,20 +10,20 @@ class TestData NUSERS = 100 # Name of the only user that is not created with a random name. - SPECIAL_USER = "admin".freeze + SPECIAL_USER = "admin" # Teams to be created. - TEAM_NAMES = [ - "bigdata", - "containers", - "dev", - "hardware", - "networking", - "ops", - "qa", - "security", - "sitereliability", - "ui" + TEAM_NAMES = %w[ + bigdata + containers + dev + hardware + networking + ops + qa + security + sitereliability + ui ].freeze # Create some random users + the admin. diff --git a/bin/rails b/bin/rails index 0e5736861..c754e036b 100755 --- a/bin/rails +++ b/bin/rails @@ -1,11 +1,11 @@ #!/usr/bin/env ruby +# frozen_string_literal: true -# rubocop:disable Lint/HandleExceptions begin load File.expand_path("../spring", __FILE__) -rescue LoadError +rescue LoadError => e + raise unless e.message.include?("spring") end -# rubocop:enable Lint/HandleExceptions APP_PATH = File.expand_path("../../config/application", __FILE__) require_relative "../config/boot" diff --git a/bin/rake b/bin/rake index a9209c892..5203529cb 100755 --- a/bin/rake +++ b/bin/rake @@ -1,11 +1,11 @@ #!/usr/bin/env ruby +# frozen_string_literal: true -# rubocop:disable Lint/HandleExceptions begin load File.expand_path("../spring", __FILE__) -rescue LoadError +rescue LoadError => e + raise unless e.message.include?("spring") end -# rubocop:enable Lint/HandleExceptions require_relative "../config/boot" require "rake" diff --git a/bin/security.rb b/bin/security.rb index 270383dc2..e7d7fd515 100644 --- a/bin/security.rb +++ b/bin/security.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/security" if ARGV.size != 2 diff --git a/bin/setup b/bin/setup index 67e27f0a4..21d5c81c0 100755 --- a/bin/setup +++ b/bin/setup @@ -1,4 +1,6 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + require "pathname" # path to your application root. diff --git a/bin/spring b/bin/spring index 6bd13be6b..a4759986d 100755 --- a/bin/spring +++ b/bin/spring @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true # This file loads spring without using Bundler, in order to be fast. # It gets overwritten when you run the `spring binstub` command. @@ -7,11 +8,9 @@ unless defined?(Spring) require "rubygems" require "bundler" - # rubocop:disable Lint/AssignmentInCondition: - if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) + if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq } gem "spring", match[1] require "spring/binstub" end - # rubocop:enable Lint/AssignmentInCondition: end diff --git a/config.ru b/config.ru index 0720e2423..0e39b99d8 100644 --- a/config.ru +++ b/config.ru @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. require ::File.expand_path("../config/environment", __FILE__) diff --git a/config/application.rb b/config/application.rb index c1c5e8416..2d02f5acf 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require File.expand_path("../boot", __FILE__) require "rails/all" @@ -7,6 +9,7 @@ Bundler.require(*Rails.groups) module Portus + # Application implements the Rails application base for Portus. class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers @@ -44,22 +47,22 @@ class Application < Rails::Application allow do origins APP_CONFIG["machine_fqdn"]["value"] resource "/api/*", - credentials: true, - headers: :any, - methods: :any, - expose: ["Link", "X-Total", "X-Total-Pages", "X-Per-Page", - "X-Page", "X-Next-Page", "X-Prev-Page"] + credentials: true, + headers: :any, + methods: :any, + expose: ["Link", "X-Total", "X-Total-Pages", "X-Per-Page", + "X-Page", "X-Next-Page", "X-Prev-Page"] end # Cross-origin requests must not have the session cookie available allow do origins "*" resource "/api/*", - credentials: false, # See the `credentials` in https://github.com/cyu/rack-cors#origin - headers: :any, - methods: :any, - expose: ["Link", "X-Total", "X-Total-Pages", "X-Per-Page", - "X-Page", "X-Next-Page", "X-Prev-Page"] + credentials: false, # See the `credentials` in https://github.com/cyu/rack-cors#origin + headers: :any, + methods: :any, + expose: ["Link", "X-Total", "X-Total-Pages", "X-Per-Page", + "X-Page", "X-Next-Page", "X-Prev-Page"] end end diff --git a/config/boot.rb b/config/boot.rb index fb24cf2ed..2a01d9e25 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) require "bundler/setup" # Set up gems listed in the Gemfile. diff --git a/config/cronotab.rb b/config/cronotab.rb index 3b0c1f98c..3fd432a32 100644 --- a/config/cronotab.rb +++ b/config/cronotab.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/migrate" env = ENV["CATALOG_CRON"] || 10 diff --git a/config/environment.rb b/config/environment.rb index 171198560..0e90cede9 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Load the Rails application. require File.expand_path("../application", __FILE__) diff --git a/config/environments/development.rb b/config/environments/development.rb index 900c24727..ed15bde84 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/config/environments/helpers/migrate.rb b/config/environments/helpers/migrate.rb new file mode 100644 index 000000000..c6ddc4f74 --- /dev/null +++ b/config/environments/helpers/migrate.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# TODO: remove this on the next version +def run_migration!(config) + return if ENV["SKIP_MIGRATION"] + + config.after_initialize do + begin + ActiveRecord::Migrator.migrate(Rails.root.join("db", "migrate"), nil) + rescue StandardError => e + warn "Error running migration: #{e.message}" + end + end +end diff --git a/config/environments/production.rb b/config/environments/production.rb index 353bdbd7b..9d3f1db92 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,4 +1,5 @@ -# rubocop:disable Metrics/BlockLength +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -50,10 +51,10 @@ # when problems arise by default. Otherwise, the user might specify its own # log level through the `PORTUS_LOG_LEVEL` environment variable. config.log_level = if ENV["PORTUS_LOG_LEVEL"] - ENV["PORTUS_LOG_LEVEL"].to_sym - else - :info - end + ENV["PORTUS_LOG_LEVEL"].to_sym + else + :info + end # Prepend all log lines with the following tags. # config.log_tags = [:subdomain, :uuid] @@ -85,16 +86,6 @@ config.active_record.dump_schema_after_migration = false # Run pending migrations - # rubocop:disable Lint/RescueWithoutErrorClass - unless ENV["SKIP_MIGRATION"] - config.after_initialize do - begin - ActiveRecord::Migrator.migrate(Rails.root.join("db", "migrate"), nil) - rescue - warn "Error running migration! Please review database configuration" - end - end - end - # rubocop:enable Lint/RescueWithoutErrorClass + require_relative "helpers/migrate" + run_migration!(config) end -# rubocop:enable Metrics/BlockLength diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 353bdbd7b..9d3f1db92 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -1,4 +1,5 @@ -# rubocop:disable Metrics/BlockLength +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -50,10 +51,10 @@ # when problems arise by default. Otherwise, the user might specify its own # log level through the `PORTUS_LOG_LEVEL` environment variable. config.log_level = if ENV["PORTUS_LOG_LEVEL"] - ENV["PORTUS_LOG_LEVEL"].to_sym - else - :info - end + ENV["PORTUS_LOG_LEVEL"].to_sym + else + :info + end # Prepend all log lines with the following tags. # config.log_tags = [:subdomain, :uuid] @@ -85,16 +86,6 @@ config.active_record.dump_schema_after_migration = false # Run pending migrations - # rubocop:disable Lint/RescueWithoutErrorClass - unless ENV["SKIP_MIGRATION"] - config.after_initialize do - begin - ActiveRecord::Migrator.migrate(Rails.root.join("db", "migrate"), nil) - rescue - warn "Error running migration! Please review database configuration" - end - end - end - # rubocop:enable Lint/RescueWithoutErrorClass + require_relative "helpers/migrate" + run_migration!(config) end -# rubocop:enable Metrics/BlockLength diff --git a/config/environments/test.rb b/config/environments/test.rb index 483736ba4..052a668d0 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 388de2d62..db1b6a016 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + Rails.application.config.assets.version = "1.0" Rails.application.config.assets.precompile += %w[*.woff2] diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 6413347a8..fbd1add62 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish diff --git a/config/initializers/checks.rb b/config/initializers/checks.rb index c33054511..d54e2cba4 100644 --- a/config/initializers/checks.rb +++ b/config/initializers/checks.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + # Clear the cache Rails.cache.write("portus-checks", nil) diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb index 7f70458de..0a23b25ec 100644 --- a/config/initializers/cookies_serializer.rb +++ b/config/initializers/cookies_serializer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 6a1317dfc..dd9859025 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,6 +1,7 @@ +# frozen_string_literal: true + # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. -# rubocop:disable Metrics/BlockLength Devise.setup do |config| # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing @@ -231,49 +232,8 @@ # The default HTTP method used to sign out a resource. Default is :delete. config.sign_out_via = :delete - # ==> OmniAuth - # Add a new OmniAuth provider. Check the wiki for more information on setting - # up on your models and hooks. - # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' - if APP_CONFIG.enabled? "oauth.google_oauth2" - # Use only setted options. - options = APP_CONFIG["oauth"]["google_oauth2"]["options"].reject { |_k, v| v.blank? } - options[:skip_jwt] = true - config.omniauth :google_oauth2, APP_CONFIG["oauth"]["google_oauth2"]["id"], - APP_CONFIG["oauth"]["google_oauth2"]["secret"], options - end - - if APP_CONFIG.enabled? "oauth.open_id" - require "openid/store/filesystem" - options = { store: OpenID::Store::Filesystem.new("/tmp") } - if APP_CONFIG["oauth"]["open_id"]["identifier"].present? - options[:identifier] = APP_CONFIG["oauth"]["open_id"]["identifier"] - end - config.omniauth :open_id, options - end - - if APP_CONFIG.enabled? "oauth.github" - config.omniauth :github, APP_CONFIG["oauth"]["github"]["client_id"], - APP_CONFIG["oauth"]["github"]["client_secret"], scope: "user,read:org" - end - - if APP_CONFIG.enabled? "oauth.gitlab" - site = if APP_CONFIG["oauth"]["gitlab"]["server"].blank? - "https://gitlab.com" - else - APP_CONFIG["oauth"]["gitlab"]["server"] - end - - config.omniauth :gitlab, APP_CONFIG["oauth"]["gitlab"]["application_id"], - APP_CONFIG["oauth"]["gitlab"]["secret"], client_options: { site: site } - end - - if APP_CONFIG.enabled? "oauth.bitbucket" - require "omni_auth/strategies/bitbucket" - options = APP_CONFIG["oauth"]["bitbucket"]["options"].reject { |_k, v| v.blank? } - config.omniauth :bitbucket, APP_CONFIG["oauth"]["bitbucket"]["key"], - APP_CONFIG["oauth"]["bitbucket"]["secret"], options - end + require_relative "devise/oauth" + configure_oauth!(config) # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or @@ -310,4 +270,3 @@ # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' end -# rubocop:enable Metrics/BlockLength diff --git a/config/initializers/devise/oauth.rb b/config/initializers/devise/oauth.rb new file mode 100644 index 000000000..c95023b86 --- /dev/null +++ b/config/initializers/devise/oauth.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +# In order to provide a new backend, you have to: +# +# 1. Add support for it on the `lib` directory or add the gem on the Gemfile. +# 2. Add a method called "#{backend}_fetch_options" on this file that returns +# the specific options to be passed to omniauth for this backend. +# 3. Add it on the hash from `configure_oauth!` by also specifying user id and +# secret if needed. + +# +# Backend-specific methods. +# + +def google_oauth2_fetch_options + options = APP_CONFIG["oauth"]["google_oauth2"]["options"].reject { |_k, v| v.blank? } + options[:skip_jwt] = true + options +end + +def open_id_fetch_options + require "openid/store/filesystem" + + options = { store: OpenID::Store::Filesystem.new("/tmp") } + + if APP_CONFIG["oauth"]["open_id"]["identifier"].present? + options[:identifier] = APP_CONFIG["oauth"]["open_id"]["identifier"] + end + options +end + +def github_fetch_options + { scope: "user,read:org" } +end + +def gitlab_fetch_options + site = if APP_CONFIG["oauth"]["gitlab"]["server"].blank? + "https://gitlab.com" + else + APP_CONFIG["oauth"]["gitlab"]["server"] + end + + { client_options: { site: site } } +end + +def bitbucket_fetch_options + require "omni_auth/strategies/bitbucket" + + APP_CONFIG["oauth"]["bitbucket"]["options"].reject { |_k, v| v.blank? } +end + +# +# General methods. +# + +# configure_backend! calls the specific `_fetch_options` method for the given +# backend and configures omniauth with the given credentials. +def configure_backend!(config, backend, id = nil, secret = nil) + return unless APP_CONFIG.enabled?("oauth.#{backend}") + + options = send("#{backend}_fetch_options") + + if id + config.omniauth backend, id, secret, options + else + config.omniauth backend, options + end +end + +# configure_oauth! will setup the initialization code for each backend. +def configure_oauth!(config) + [ + { backend: :google_oauth2, id: "id", secret: "secret" }, + { backend: :open_id }, + { backend: :github, id: "client_id", secret: "client_secret" }, + { backend: :gitlab, id: "application_id", secret: "secret" }, + { backend: :bitbucket, id: "key", secret: "secret" } + ].each do |b| + if b[:id] + id = APP_CONFIG["oauth"][b[:backend].to_s][b[:id]] + secret = APP_CONFIG["oauth"][b[:backend].to_s][b[:secret]] + else + id = nil + secret = nil + end + + configure_backend!(config, b[:backend], id, secret) + end +end diff --git a/config/initializers/environment_check.rb b/config/initializers/environment_check.rb index f50a168f2..0cd103c63 100644 --- a/config/initializers/environment_check.rb +++ b/config/initializers/environment_check.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file checks for important environment variables. Some of them have to be # set in order for Portus to work in certain scenarios (e.g. secret key base on # production), others are strong recommendations. @@ -13,11 +15,16 @@ def mandatory_secret!(env, value) "mandatory in production because it's needed for the generation of secrets." end +# Checks an env. variable related to the DB and checks it. +def db(param) + name = "PORTUS_PRODUCTION_#{param.upcase}" + other = "PORTUS_DB_#{param.upcase}" + + ENV[name].present? && ENV[other].blank? +end + # Database Environment Variables have changed. -if ENV["PORTUS_PRODUCTION_HOST"].present? && ENV["PORTUS_DB_HOST"].blank? || - ENV["PORTUS_PRODUCTION_USERNAME"].present? && ENV["PORTUS_DB_USERNAME"].blank? || - ENV["PORTUS_PRODUCTION_PASSWORD"].present? && ENV["PORTUS_DB_PASSWORD"].blank? || - ENV["PORTUS_PRODUCTION_DATABASE"].present? && ENV["PORTUS_DB_DATABASE"].blank? +if db("host") || db("username") || db("password") || db("database") raise Portus::DeprecationError, "The database configuration has been extended. With this " \ "extension the Environment Variable Names have been changed. Instead of starting with " \ "'PORTUS_PRODUCTION_' they now start with 'PORTUS_DB_'. Please consolidate " \ diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 4a994e1e7..7a4f47b4c 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. diff --git a/config/initializers/gravatar_image_tag.rb b/config/initializers/gravatar_image_tag.rb index 4189a1d7c..00cc92596 100644 --- a/config/initializers/gravatar_image_tag.rb +++ b/config/initializers/gravatar_image_tag.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + GravatarImageTag.configure do |config| config.default_image = :identicon config.include_size_attributes = true diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index ac033bf9d..aa7435fbc 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections diff --git a/config/initializers/ldap_authenticatable.rb b/config/initializers/ldap_authenticatable.rb index c7f29c780..b26644764 100644 --- a/config/initializers/ldap_authenticatable.rb +++ b/config/initializers/ldap_authenticatable.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + require "portus/ldap" Warden::Strategies.add(:ldap_authenticatable, Portus::LDAP) diff --git a/config/initializers/mailer_url_options.rb b/config/initializers/mailer_url_options.rb index b9f65b60c..8b10453b3 100644 --- a/config/initializers/mailer_url_options.rb +++ b/config/initializers/mailer_url_options.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + # If you're on staging/production, then you must be using SSL. Moreover, if # you're on development mode and you have set PORTUS_USE_SSL, then SSL will also # be required. Otherwise, we will fallback to regular HTTP. protocol = if !Rails.env.development? || !ENV["PORTUS_USE_SSL"].nil? - "https://" -else - "http://" -end + "https://" + else + "http://" + end host = APP_CONFIG["machine_fqdn"]["value"] ActionMailer::Base.default_url_options[:host] = host diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index dc1899682..6e1d16f02 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: diff --git a/config/initializers/secure_random_base58.rb b/config/initializers/secure_random_base58.rb index 372bd67ed..3731f87ab 100644 --- a/config/initializers/secure_random_base58.rb +++ b/config/initializers/secure_random_base58.rb @@ -1,7 +1,10 @@ -# TODO: remove me when new minor rails version released -# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/securerandom.rb +# frozen_string_literal: true + require "securerandom" +# SecureRandom is a module that implements a feature available in Rails 5.0. +# TODO: remove me when we upgrade to Rails 5.0 +# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/securerandom.rb module SecureRandom BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - %w[0 O I l] diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 9c1ac777b..4f2149e4d 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: "_portus_session" diff --git a/config/initializers/smtp.rb b/config/initializers/smtp.rb index 967d7c42e..9a59dff59 100644 --- a/config/initializers/smtp.rb +++ b/config/initializers/smtp.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # If SMTP was set, then use it as the delivery method and configure it with the # given config. diff --git a/config/initializers/swagger.rb b/config/initializers/swagger.rb index ae22742ea..7165091f2 100644 --- a/config/initializers/swagger.rb +++ b/config/initializers/swagger.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + unless Rails.env.production? protocol = ::APP_CONFIG.enabled?("check_ssl_usage") ? "https://" : "http://" diff --git a/config/initializers/version.rb b/config/initializers/version.rb index 50097aaad..b032017b7 100644 --- a/config/initializers/version.rb +++ b/config/initializers/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Version module # Makes the app version available to the application itself # Needs the git executable for all git operations @@ -17,8 +19,8 @@ def self.git? COMMIT = Version.git? ? `git log --pretty=format:'%h' -n 1 2>/dev/null`.chomp : nil TAG = Version.git? ? `git tag --points-at $(git rev-parse HEAD) 2>/dev/null`.chomp : nil BRANCH = if Version.git? - `git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3 2>/dev/null`.chomp - end + `git symbolic-ref HEAD 2>/dev/null | cut -d"/" -f 3 2>/dev/null`.chomp + end # Read the version from the file. def self.from_file diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index 33725e95f..246168a42 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which diff --git a/config/puma.rb b/config/puma.rb index 7a84dce78..dd2945fc9 100755 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,4 +1,5 @@ #!/usr/bin/env puma +# frozen_string_literal: true # Set CConfig straight. ENV["CCONFIG_PREFIX"] = "PORTUS" diff --git a/config/routes.rb b/config/routes.rb index 6af96d098..6499703bf 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,10 @@ +# frozen_string_literal: true + +# rubocop:disable Metrics/BlockLength +# TODO: see https://github.com/SUSE/Portus/issues/1469 Rails.application.routes.draw do resources :errors, only: [:show] - resources :teams, only: [:index, :show, :update] do + resources :teams, only: %i[index show update] do member do get "typeahead/:query" => "teams#typeahead", :defaults => { format: "json" } end @@ -9,11 +13,11 @@ resources :help, only: [:index] - resources :team_users, only: [:create, :destroy, :update] - resources :namespaces, only: [:index, :show, :update] do + resources :team_users, only: %i[create destroy update] + resources :namespaces, only: %i[index show update] do put "change_visibility", on: :member resources :webhooks do - resources :headers, only: [:create, :destroy], controller: :webhook_headers + resources :headers, only: %i[create destroy], controller: :webhook_headers resources :deliveries, only: [:update], controller: :webhook_deliveries member do put "toggle_enabled" @@ -22,14 +26,14 @@ end get "namespaces/typeahead/:query" => "namespaces#typeahead", :defaults => { format: "json" } - resources :repositories, only: [:index, :show, :destroy] do + resources :repositories, only: %i[index show destroy] do post :toggle_star, on: :member - resources :comments, only: [:create, :destroy] + resources :comments, only: %i[create destroy] end - resources :tags, only: [:show, :destroy] + resources :tags, only: %i[show destroy] - resources :application_tokens, only: [:create, :destroy] + resources :application_tokens, only: %i[create destroy] devise_for :users, controllers: { registrations: "auth/registrations", sessions: "auth/sessions", @@ -65,7 +69,7 @@ namespace :admin do resources :activities, only: [:index] resources :dashboard, only: [:index] - resources :registries, except: [:show, :destroy] + resources :registries, except: %i[show destroy] resources :namespaces, only: [:index] resources :teams, only: [:index] resources :users do @@ -78,3 +82,4 @@ get "/#{code}", to: "errors#show", status: code end end +# rubocop:enable Metrics/BlockLength diff --git a/config/rubocop-suse.yml b/config/rubocop-suse.yml deleted file mode 100644 index ce1606424..000000000 --- a/config/rubocop-suse.yml +++ /dev/null @@ -1,60 +0,0 @@ -# This is the shared Rubocop configuration for SUSE projects. It is maintained -# at https://github.com/SUSE/style-guides/blob/master/rubocop-suse.yml -# -# The configuration is tested and used with the Rubocop version used by Hound -# (http://hound-ci.com). -# -# We use the default Hound config as a baseline: -# -# https://raw.githubusercontent.com/thoughtbot/hound/master/config/style_guides/ruby.yml -# -# This file contains the rules with derive from this. - -Lint/EndAlignment: - EnforcedStyleAlignWith: variable - -Metrics/AbcSize: - Max: 30 - -Metrics/LineLength: - Max: 100 - # To make it possible to copy or click on URIs in the code, we allow lines - # contaning a URI to be longer than Max. - AllowURI: true - URISchemes: - - http - - https - -Layout/AlignHash: - EnforcedHashRocketStyle: table - EnforcedColonStyle: table - -Layout/AlignParameters: - Enabled: false - -Style/CollectionMethods: - Enabled: false - -Layout/EmptyLinesAroundBlockBody: - Enabled: false - -Layout/MultilineOperationIndentation: - EnforcedStyle: indented - -Style/StringLiterals: - EnforcedStyle: double_quotes - -Style/StringLiteralsInInterpolation: - EnforcedStyle: double_quotes - -Style/WordArray: - Enabled: false - -Style/RegexpLiteral: - Enabled: false - -Style/SignalException: - EnforcedStyle: only_raise - -Style/NumericLiterals: - Enabled: false diff --git a/db/seeds.rb b/db/seeds.rb index a7c6ca803..67b8686b2 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Adding the Portus user. if User.any? diff --git a/deploy/before_migrate.rb b/deploy/before_migrate.rb index 778266485..89abf9e76 100644 --- a/deploy/before_migrate.rb +++ b/deploy/before_migrate.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + rails_env = new_resource.environment["RAILS_ENV"] secret_key = new_resource.environment["SECRET_KEY_BASE"] Chef::Log.info("Precompiling assets for RAILS_ENV=#{rails_env}...") diff --git a/examples/development/vagrant/setup_private_network b/examples/development/vagrant/setup_private_network index 0b807dfc9..364aa3b40 100755 --- a/examples/development/vagrant/setup_private_network +++ b/examples/development/vagrant/setup_private_network @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true require "fileutils" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index aebfe8ead..cb69bf2ab 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1,4 +1,8 @@ +# frozen_string_literal: true + module API + # Entities is a module that groups all the classes to be used as Grape + # entities. module Entities # General entities @@ -95,11 +99,7 @@ class Tags < Grape::Entity class Repositories < Grape::Entity expose :id, documentation: { type: Integer, desc: "Repository ID" } expose :name, documentation: { type: String, desc: "Repository name" } - # rubocop:disable Style/SymbolProc - expose :full_name, documentation: { type: String, desc: "Repository full name" } do |r| - r.full_name - end - # rubocop:enable Style/SymbolProc + expose :full_name, documentation: { type: String, desc: "Repository full name" } expose :created_at, :updated_at, documentation: { type: DateTime } expose :namespace, documentation: { desc: "The ID of the namespace containing this repository" diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 62d01b932..46dd9a6b9 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/auth_from_token" module API diff --git a/lib/api/root_api.rb b/lib/api/root_api.rb index b2a4c88c5..66cc91642 100644 --- a/lib/api/root_api.rb +++ b/lib/api/root_api.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "grape-swagger" require "api/entities" diff --git a/lib/api/v1/health.rb b/lib/api/v1/health.rb index 88832de52..4522476d5 100644 --- a/lib/api/v1/health.rb +++ b/lib/api/v1/health.rb @@ -1,7 +1,11 @@ +# frozen_string_literal: true + require "portus/health" module API module V1 + # Health implements endpoints that report on the health status of the API or + # other components. class Health < Grape::API version "v1", using: :path @@ -10,8 +14,8 @@ class Health < Grape::API resource :health do desc "Returns hash of metrics", - tags: ["health"], - detail: "Returns general metrics on the health of the system" + tags: ["health"], + detail: "Returns general metrics on the health of the system" get do response, success = ::Portus::Health.check diff --git a/lib/api/v1/namespaces.rb b/lib/api/v1/namespaces.rb index a22d7ddfa..4ad9bcda6 100644 --- a/lib/api/v1/namespaces.rb +++ b/lib/api/v1/namespaces.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + module API module V1 + # Namespaces implements all the endpoints regarding namespaces. class Namespaces < Grape::API version "v1", using: :path @@ -11,14 +14,14 @@ class Namespaces < Grape::API helpers ::API::Helpers::Namespaces desc "Returns a list of namespaces.", - tags: ["namespaces"], - detail: "This will expose all accessible namespaces.", - is_array: true, - entity: API::Entities::Namespaces, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + tags: ["namespaces"], + detail: "This will expose all accessible namespaces.", + is_array: true, + entity: API::Entities::Namespaces, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] get do present accessible_namespaces, @@ -48,11 +51,11 @@ class Namespaces < Grape::API end desc "Create a namespace", - entity: API::Entities::Teams, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + entity: API::Entities::Teams, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] params do requires :name, type: String, documentation: { desc: "Namespace name." } @@ -79,14 +82,14 @@ class Namespaces < Grape::API route_param :id, type: String, requirements: { id: /.*/ } do resource :repositories do desc "Returns the list of the repositories for the given namespace.", - params: API::Entities::Namespaces.documentation.slice(:id), - is_array: true, - entity: API::Entities::Repositories, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Namespaces.documentation.slice(:id), + is_array: true, + entity: API::Entities::Repositories, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] get do namespace = Namespace.find params[:id] @@ -98,12 +101,12 @@ class Namespaces < Grape::API end desc "Show namespaces by id.", - entity: API::Entities::Namespaces, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + entity: API::Entities::Namespaces, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] params do requires :id, type: String, documentation: { desc: "Namespace ID." } diff --git a/lib/api/v1/registries.rb b/lib/api/v1/registries.rb index 9e574eb72..a718ad384 100644 --- a/lib/api/v1/registries.rb +++ b/lib/api/v1/registries.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + module API module V1 + # Registries implements all the endpoints regarding registries. class Registries < Grape::API version "v1", using: :path @@ -9,40 +12,40 @@ class Registries < Grape::API end desc "Returns a list of registries", - tags: ["registries"], - detail: "This will expose all accessible registries.", - is_array: true, - entity: API::Entities::Registries, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + tags: ["registries"], + detail: "This will expose all accessible registries.", + is_array: true, + entity: API::Entities::Registries, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] get do present Registry.all, with: API::Entities::Registries end desc "Validates the given registry", - tags: ["registries"], - detail: "Besides containing the usual Status object, it adds the reachable " \ - "validation to the `hostname` field in the `messages` hash. This validation " \ - "returns a string containing the error as given by the registry. If empty " \ - "then everything went well", - entity: API::Entities::Status, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + tags: ["registries"], + detail: "Besides containing the usual Status object, it adds the reachable " \ + "validation to the `hostname` field in the `messages` hash. This validation "\ + "returns a string containing the error as given by the registry. If empty " \ + "then everything went well", + entity: API::Entities::Status, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] params do requires :name, - using: API::Entities::Registries.documentation.slice(:name) + using: API::Entities::Registries.documentation.slice(:name) requires :hostname, - using: API::Entities::Registries.documentation.slice(:hostname) + using: API::Entities::Registries.documentation.slice(:hostname) optional :external_hostname, - using: API::Entities::Registries.documentation.slice(:external_hostname) + using: API::Entities::Registries.documentation.slice(:external_hostname) requires :use_ssl, - using: API::Entities::Registries.documentation.slice(:use_ssl) + using: API::Entities::Registries.documentation.slice(:use_ssl) optional :only, type: Array[String] end diff --git a/lib/api/v1/repositories.rb b/lib/api/v1/repositories.rb index 6bd34d3fc..0782140e0 100644 --- a/lib/api/v1/repositories.rb +++ b/lib/api/v1/repositories.rb @@ -1,5 +1,10 @@ +# frozen_string_literal: true + module API module V1 + # Repositories implements all the endpoints regarding repositories and some + # endpoints regarding tags that might be convenient to use as a + # sub-resource. class Repositories < Grape::API version "v1", using: :path @@ -9,14 +14,14 @@ class Repositories < Grape::API end desc "Returns list of repositories.", - tags: ["repositories"], - detail: "This will expose all repositories.", - is_array: true, - entity: API::Entities::Repositories, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + tags: ["repositories"], + detail: "This will expose all repositories.", + is_array: true, + entity: API::Entities::Repositories, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] get do present policy_scope(Repository), with: API::Entities::Repositories @@ -25,14 +30,14 @@ class Repositories < Grape::API route_param :id, type: String, requirements: { id: /.*/ } do resource :tags do desc "Returns the list of the tags for the given repository.", - params: API::Entities::Repositories.documentation.slice(:id), - is_array: true, - entity: API::Entities::Tags, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Repositories.documentation.slice(:id), + is_array: true, + entity: API::Entities::Tags, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] get do repo = Repository.find params[:id] @@ -41,14 +46,14 @@ class Repositories < Grape::API end desc "Returns the list of the tags for the given repository groupped by digest.", - params: API::Entities::Repositories.documentation.slice(:id), - is_array: true, - entity: API::Entities::Tags, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Repositories.documentation.slice(:id), + is_array: true, + entity: API::Entities::Tags, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] get "/grouped" do repo = Repository.find params[:id] @@ -83,12 +88,12 @@ class Repositories < Grape::API end desc "Show repositories by id.", - entity: API::Entities::Repositories, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + entity: API::Entities::Repositories, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] params do requires :id, type: String, documentation: { desc: "Repository ID." } diff --git a/lib/api/v1/tags.rb b/lib/api/v1/tags.rb index 8566ab252..cba47ebc6 100644 --- a/lib/api/v1/tags.rb +++ b/lib/api/v1/tags.rb @@ -1,5 +1,9 @@ +# frozen_string_literal: true + module API module V1 + # Tags implements all the endpoints regarding tags that have not been + # addressed in other classes. class Tags < Grape::API version "v1", using: :path diff --git a/lib/api/v1/teams.rb b/lib/api/v1/teams.rb index 3f09d5c33..275e427ea 100644 --- a/lib/api/v1/teams.rb +++ b/lib/api/v1/teams.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module API module V1 class Teams < Grape::API @@ -9,25 +11,25 @@ class Teams < Grape::API end desc "Returns list of teams.", - tags: ["teams"], - detail: "This will expose all teams.", - is_array: true, - entity: API::Entities::Teams, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + tags: ["teams"], + detail: "This will expose all teams.", + is_array: true, + entity: API::Entities::Teams, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] get do present policy_scope(Team), with: API::Entities::Teams end desc "Create a team", - entity: API::Entities::Teams, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + entity: API::Entities::Teams, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] params do requires :name, type: String, documentation: { desc: "Team name." } @@ -52,14 +54,14 @@ class Teams < Grape::API route_param :id, type: String, requirements: { id: /.*/ } do resource :namespaces do desc "Returns the list of namespaces for the given team", - params: API::Entities::Teams.documentation.slice(:id), - is_array: true, - entity: API::Entities::Namespaces, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Teams.documentation.slice(:id), + is_array: true, + entity: API::Entities::Namespaces, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] get do team = Team.find params[:id] @@ -70,14 +72,14 @@ class Teams < Grape::API resource :members do desc "Returns the list of team members", - params: API::Entities::Teams.documentation.slice(:id), - is_array: true, - entity: API::Entities::Users, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Teams.documentation.slice(:id), + is_array: true, + entity: API::Entities::Users, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] get do team = Team.find params[:id] @@ -87,12 +89,12 @@ class Teams < Grape::API end desc "Show teams by id.", - entity: API::Entities::Teams, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + entity: API::Entities::Teams, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] params do requires :id, type: String, documentation: { desc: "Team ID." } diff --git a/lib/api/v1/users.rb b/lib/api/v1/users.rb index 38ee89206..109c82ff1 100644 --- a/lib/api/v1/users.rb +++ b/lib/api/v1/users.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + module API module V1 + # Users implements all the endpoints regarding users and application tokens. class Users < Grape::API version "v1", using: :path @@ -12,32 +15,32 @@ class Users < Grape::API resource :application_tokens do # List application tokens beloged to user with given :id. desc "Returns list of user's tokens.", - params: API::Entities::Users.documentation.slice(:id), - is_array: true, - entity: API::Entities::ApplicationTokens, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Users.documentation.slice(:id), + is_array: true, + entity: API::Entities::ApplicationTokens, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] get do user = User.find params[:id] present user.application_tokens, - with: API::Entities::ApplicationTokens + with: API::Entities::ApplicationTokens end # Create application token for user with given :id. desc "Create user's token.", - params: API::Entities::Users.documentation.slice(:id), - success: { code: 200 }, - entity: API::Entities::ApplicationTokens, - failure: [ - [400, "Bad request.", API::Entities::ApiErrors], - [401, "Authentication fails."], - [403, "Authorization fails."] - ], - consumes: ["application/x-www-form-urlencoded", "application/json"] + params: API::Entities::Users.documentation.slice(:id), + success: { code: 200 }, + entity: API::Entities::ApplicationTokens, + failure: [ + [400, "Bad request.", API::Entities::ApiErrors], + [401, "Authentication fails."], + [403, "Authorization fails."] + ], + consumes: ["application/x-www-form-urlencoded", "application/json"] params do requires :application, documentation: { desc: "Application name" } @@ -63,11 +66,11 @@ class Users < Grape::API resource :application_tokens do desc "Delete application token.", - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] params do requires :id, documentation: { desc: "Token id" } @@ -82,22 +85,22 @@ class Users < Grape::API end desc "Create new user.", - failure: [ - [400, "Bad request.", API::Entities::ApiErrors], - [401, "Authentication fails."], - [403, "Authorization fails."] - ], - consumes: ["application/x-www-form-urlencoded", "application/json"] + failure: [ + [400, "Bad request.", API::Entities::ApiErrors], + [401, "Authentication fails."], + [403, "Authorization fails."] + ], + consumes: ["application/x-www-form-urlencoded", "application/json"] params do requires :user, type: Hash do requires :all, - only: [:username, :email], - using: API::Entities::Users.documentation.slice(:username, :email) + only: %i[username email], + using: API::Entities::Users.documentation.slice(:username, :email) requires :password, type: String optional :all, - only: [:display_name], - using: API::Entities::Users.documentation.slice(:display_name) + only: [:display_name], + using: API::Entities::Users.documentation.slice(:display_name) end end @@ -113,24 +116,24 @@ class Users < Grape::API # Update user with given :id. desc "Update user.", - params: API::Entities::Users.documentation.slice(:id), - failure: [ - [400, "Bad request.", API::Entities::ApiErrors], - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ], - consumes: ["application/x-www-form-urlencoded", "application/json"] + params: API::Entities::Users.documentation.slice(:id), + failure: [ + [400, "Bad request.", API::Entities::ApiErrors], + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ], + consumes: ["application/x-www-form-urlencoded", "application/json"] params do requires :user, type: Hash do optional :all, - only: [:username, :email], - using: API::Entities::Users.documentation.slice(:username, :email) + only: %i[username email], + using: API::Entities::Users.documentation.slice(:username, :email) optional :password, type: String, desc: "Password" optional :all, - only: [:display_name], - using: API::Entities::Users.documentation.slice(:display_name) + only: [:display_name], + using: API::Entities::Users.documentation.slice(:display_name) end end @@ -147,12 +150,12 @@ class Users < Grape::API # Delete user with given :id. desc "Delete user.", - params: API::Entities::Users.documentation.slice(:id), - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + params: API::Entities::Users.documentation.slice(:id), + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] delete ":id" do user = User.find(params[:id]) @@ -162,14 +165,14 @@ class Users < Grape::API end desc "Returns list of users.", - tags: ["users"], - detail: "This will expose all users.", - is_array: true, - entity: API::Entities::Users, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."] - ] + tags: ["users"], + detail: "This will expose all users.", + is_array: true, + entity: API::Entities::Users, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."] + ] get do users = User.all @@ -177,15 +180,14 @@ class Users < Grape::API end route_param :id, type: String, requirements: { id: /.*/ } do - # Find user by id or email and return. desc "Show user by id or email.", - entity: API::Entities::Users, - failure: [ - [401, "Authentication fails."], - [403, "Authorization fails."], - [404, "Not found."] - ] + entity: API::Entities::Users, + failure: [ + [401, "Authentication fails."], + [403, "Authorization fails."], + [404, "Not found."] + ] params do requires :id, type: String, documentation: { desc: "User id or email." } diff --git a/lib/api/version.rb b/lib/api/version.rb index 6d16be588..71b320f32 100644 --- a/lib/api/version.rb +++ b/lib/api/version.rb @@ -1,4 +1,8 @@ +# frozen_string_literal: true + module API + # Version implements the main "/version" endpoint. It's not versioned because + # this is meant to be stable throughout any version of the API. class Version < Grape::API before do authorization!(force_admin: false) @@ -11,12 +15,12 @@ class Version < Grape::API get "/version" do version = ::Version.from_file git = if ::Version.git? - if ::Version::TAG.present? - { tag: ::Version::TAG } - else - { branch: ::Version::BRANCH, commit: ::Version::COMMIT } - end - end + if ::Version::TAG.present? + { tag: ::Version::TAG } + else + { branch: ::Version::BRANCH, commit: ::Version::COMMIT } + end + end { "api-versions": ["v1"], diff --git a/lib/man_pages.rb b/lib/man_pages.rb index 8b935b92d..b0808d925 100644 --- a/lib/man_pages.rb +++ b/lib/man_pages.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: require "md2man/roff/engine" @@ -5,10 +7,10 @@ # different places. class ManPages # The path were the markdown files are being stored. - MARKDOWN_PATH = "packaging/suse/portusctl/man/markdown".freeze + MARKDOWN_PATH = "packaging/suse/portusctl/man/markdown" # The path were the resulting man pages are being stored. - MAN_PATH = "packaging/suse/portusctl/man/man1".freeze + MAN_PATH = "packaging/suse/portusctl/man/man1" def initialize @markdown_files = Dir.glob(Rails.root.join(MARKDOWN_PATH, "*.md")) @@ -22,7 +24,7 @@ def render_markdown(file) # Returns the name and the path of the corresponding man page of the given # markdown file. def corresponding_man(file) - name = file.match(/\/([\w-]+)\.md/)[1] + name = file.match(%r{/([\w-]+)\.md})[1] path = Rails.root.join(MAN_PATH, "#{name}.1") [name, path] end diff --git a/lib/omni_auth/strategies/bitbucket.rb b/lib/omni_auth/strategies/bitbucket.rb index 1449b985b..595ba23e3 100644 --- a/lib/omni_auth/strategies/bitbucket.rb +++ b/lib/omni_auth/strategies/bitbucket.rb @@ -1,13 +1,16 @@ +# frozen_string_literal: true + require "omniauth-oauth2" module OmniAuth module Strategies + # Bitbucket implements the OAuth2 protocol for bitbucket. class Bitbucket < OmniAuth::Strategies::OAuth2 option :name, "bitbucket" option :client_options, - site: "https://bitbucket.org", - authorize_url: "https://bitbucket.org/site/oauth2/authorize", - token_url: "https://bitbucket.org/site/oauth2/access_token" + site: "https://bitbucket.org", + authorize_url: "https://bitbucket.org/site/oauth2/authorize", + token_url: "https://bitbucket.org/site/oauth2/access_token" uid { raw_info["uuid"].to_s } diff --git a/lib/portus/auth_from_token.rb b/lib/portus/auth_from_token.rb index e8a5625c8..c4cf9629e 100644 --- a/lib/portus/auth_from_token.rb +++ b/lib/portus/auth_from_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus # AuthFromToken includes methods for authenticating users through an # application token. This may apply to either controllers or the Rest API, and diff --git a/lib/portus/auth_scope.rb b/lib/portus/auth_scope.rb index ace51c53a..412c3561b 100644 --- a/lib/portus/auth_scope.rb +++ b/lib/portus/auth_scope.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus # This is the base class for AuthScope classes. An AuthScope class retrieves # the information that can be extracted from a Docker scope string for the diff --git a/lib/portus/background/security_scanning.rb b/lib/portus/background/security_scanning.rb index 88bd42448..dbd10686a 100644 --- a/lib/portus/background/security_scanning.rb +++ b/lib/portus/background/security_scanning.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/security" module Portus diff --git a/lib/portus/checks.rb b/lib/portus/checks.rb index 0706160b5..80804d449 100644 --- a/lib/portus/checks.rb +++ b/lib/portus/checks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus # Performs some checks on runtime to validate that some settings from Portus # are properly set. diff --git a/lib/portus/db.rb b/lib/portus/db.rb index abe3877bb..eb40e7953 100644 --- a/lib/portus/db.rb +++ b/lib/portus/db.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus # The DB module has useful methods for DB purposes. module DB diff --git a/lib/portus/deprecation_error.rb b/lib/portus/deprecation_error.rb index a33968c8e..5d5d30552 100644 --- a/lib/portus/deprecation_error.rb +++ b/lib/portus/deprecation_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus # DeprecationError is the exception to be raised when certain functionality has been deprecated # in the latest version and we want to provide migration instructions diff --git a/lib/portus/errors.rb b/lib/portus/errors.rb new file mode 100644 index 000000000..8e4a0a5ff --- /dev/null +++ b/lib/portus/errors.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Portus + # Errors contain registry-specific errors that have no real implementation. + module Errors + # As specified in the token specification of distribution, the client will + # get a 401 on the first attempt of logging in, but in there should be the + # "WWW-Authenticate" header. This exception will be raised when there's no + # authentication token bearer. + class NoBearerRealmException < RuntimeError; end + + # Raised when the authorization token could not be fetched. + class AuthorizationError < RuntimeError; end + + # Used when a resource was not found for the given endpoint. + class NotFoundError < RuntimeError; end + + # Raised if this client does not have the credentials to perform an API call. + class CredentialsMissingError < RuntimeError; end + end +end diff --git a/lib/portus/health.rb b/lib/portus/health.rb index b3701891e..3f2e43a28 100644 --- a/lib/portus/health.rb +++ b/lib/portus/health.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/health_checks/db" require "portus/health_checks/registry" require "portus/health_checks/clair" diff --git a/lib/portus/health_checks/clair.rb b/lib/portus/health_checks/clair.rb index 17eefa31e..7b09b3f29 100644 --- a/lib/portus/health_checks/clair.rb +++ b/lib/portus/health_checks/clair.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/http_helpers" module Portus diff --git a/lib/portus/health_checks/db.rb b/lib/portus/health_checks/db.rb index a7eab6485..1e1695fc3 100644 --- a/lib/portus/health_checks/db.rb +++ b/lib/portus/health_checks/db.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/db" module Portus diff --git a/lib/portus/health_checks/registry.rb b/lib/portus/health_checks/registry.rb index ab1f7880d..40d137e07 100644 --- a/lib/portus/health_checks/registry.rb +++ b/lib/portus/health_checks/registry.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus module HealthChecks # Registry offers health check support for the configured Docker diff --git a/lib/portus/http_helpers.rb b/lib/portus/http_helpers.rb index 2c110b962..4515465f5 100644 --- a/lib/portus/http_helpers.rb +++ b/lib/portus/http_helpers.rb @@ -1,4 +1,8 @@ +# frozen_string_literal: true + require "net/http" +require "portus/errors" +require "portus/request_error" module Portus # Implements all the methods and classes that are needed by the RegistryClient. @@ -6,20 +10,7 @@ module Portus # the authentication process. The RegistryClient class will just deal with each # endpoint of the API. module HttpHelpers - # As specified in the token specification of distribution, the client will - # get a 401 on the first attempt of logging in, but in there should be the - # "WWW-Authenticate" header. This exception will be raised when there's no - # authentication token bearer. - class NoBearerRealmException < RuntimeError; end - - # Raised when the authorization token could not be fetched. - class AuthorizationError < RuntimeError; end - - # Used when a resource was not found for the given endpoint. - class NotFoundError < RuntimeError; end - - # Raised if this client does not have the credentials to perform an API call. - class CredentialsMissingError < RuntimeError; end + include ::Portus::Errors # Returns an URI object and a request object for the given path & method # pair. @@ -65,6 +56,26 @@ def perform_request(path, method = "get", request_auth_token = true) res end + # safe_quest simply calls perform_request and wraps any kind of exception + # into a RequestError. This way, callers don't have to check for the myriad + # of exceptions that an HTTP request might entail. + def safe_request(path, method = "get", request_auth_token = true) + perform_request(path, method, request_auth_token) + rescue Errno::ECONNREFUSED, SocketError => e + raise ::Portus::RequestError.new(exception: e, message: "connection refused") + rescue Errno::ETIMEDOUT, Net::OpenTimeout => e + raise ::Portus::RequestError.new(exception: e, message: "connection timed out") + rescue Net::HTTPBadResponse => e + raise ::Portus::RequestError.new(exception: e, + message: "there's something wrong with your SSL config") + rescue OpenSSL::SSL::SSLError => e + raise ::Portus::RequestError.new(exception: e, + message: "SSL error while communicating with the registry") + rescue StandardError => e + raise ::Portus::RequestError.new(exception: e, + message: "something went wrong. Check your configuration") + end + # Handle a known error from Docker distribution. Typically these are # responses that have an HTTP code of 40x. The given response is the raw # response as given by the registry, and the params hash are extra arguments diff --git a/lib/portus/jwt_token.rb b/lib/portus/jwt_token.rb index f8e64e67f..a4a872368 100644 --- a/lib/portus/jwt_token.rb +++ b/lib/portus/jwt_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/migrate" module Portus diff --git a/lib/portus/ldap.rb b/lib/portus/ldap.rb index ba665557e..2d6ae2442 100644 --- a/lib/portus/ldap.rb +++ b/lib/portus/ldap.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "net/ldap" require "devise/strategies/authenticatable" diff --git a/lib/portus/migrate.rb b/lib/portus/migrate.rb index c5f612b65..a978a40de 100644 --- a/lib/portus/migrate.rb +++ b/lib/portus/migrate.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/PerceivedComplexity module Portus @@ -28,7 +30,7 @@ def self.from_humanized_time(duration, default) raise DeprecationError, "The 'x.minutes' format is deprecated for configuration values " \ "such as `jwt_expiration_time`. From now on these values are " \ "expected to be integers representing minutes." - elsif value > 0 + elsif value.positive? # If it's a string containing a positive number, then convert it and return it. value.minutes else @@ -50,5 +52,6 @@ def self.registry_config(key) end end end -# rubocop:enable Metrics/PerceivedComplexity + # rubocop:enable Metrics/CyclomaticComplexity +# rubocop:enable Metrics/PerceivedComplexity diff --git a/lib/portus/registry_client.rb b/lib/portus/registry_client.rb index c712afd96..260e7f4bf 100644 --- a/lib/portus/registry_client.rb +++ b/lib/portus/registry_client.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Portus # RegistryClient is a a layer between Portus and the Registry. Given a set of # credentials, it's able to call to any endpoint in the registry API. Moreover, @@ -9,6 +11,10 @@ class RegistryClient include HttpHelpers + # ManifestError is the exception that it will be raised when a manifest + # fetch has given a bad HTTP status code. + class ManifestError < StandardError; end + # Exception being raised when we get an error from the Registry API that we # don't know how to handle. class RegistryError < StandardError; end @@ -24,9 +30,9 @@ def initialize(host, use_ssl = false, username = nil, password = nil) end # Returns whether the registry is reachable with the given credentials or - # not. + # not. This might raise a RequestError on failure. def reachable? - res = perform_request("", "get", false) + res = safe_request("", "get", false) # If a 401 was retrieved, it means that at least the registry has been # contacted. In order to get a 200, this registry should be created and @@ -46,7 +52,7 @@ def reachable? # It will raise either a ManifestNotFoundError or a RuntimeError if # something goes wrong. def manifest(repository, tag = "latest") - res = perform_request("#{repository}/manifests/#{tag}", "get") + res = safe_request("#{repository}/manifests/#{tag}", "get") if res.code.to_i == 200 mf = JSON.parse(res.body) @@ -57,8 +63,9 @@ def manifest(repository, tag = "latest") elsif res.code.to_i == 404 handle_error res, repository: repository, tag: tag else - raise "Something went wrong while fetching manifest for " \ - "#{repository}:#{tag}:[#{res.code}] - #{res.body}" + raise ::Portus::RegistryClient::ManifestError, + "Something went wrong while fetching manifest for " \ + "#{repository}:#{tag}:[#{res.code}] - #{res.body}" end end @@ -90,8 +97,8 @@ def delete(name, digest, object = "blobs") handle_error res, name: name, digest: digest else raise ::Portus::RegistryClient::RegistryError, - "Something went wrong while deleting blob: " \ - "[#{res.code}] - #{res.body}" + "Something went wrong while deleting blob: " \ + "[#{res.code}] - #{res.body}" end end @@ -125,8 +132,8 @@ def get_page(link) handle_error res else raise ::Portus::RegistryClient::RegistryError, - "Something went wrong while fetching the catalog " \ - "Response: [#{res.code}] - #{res.body}" + "Something went wrong while fetching the catalog " \ + "Response: [#{res.code}] - #{res.body}" end end diff --git a/lib/portus/registry_notification.rb b/lib/portus/registry_notification.rb index 14d3c978a..0632396cd 100644 --- a/lib/portus/registry_notification.rb +++ b/lib/portus/registry_notification.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module Portus # Handle an event as given by the Registry and processes it so it can be # consumed later on. class RegistryNotification # An array with the events that a handler has to support. - HANDLED_EVENTS = ["push", "delete"].freeze + HANDLED_EVENTS = %w[push delete].freeze # Processes the notification data with the given handlers. The data is the # parsed JSON body as given by the registry. A handler is a class that can diff --git a/lib/portus/request_error.rb b/lib/portus/request_error.rb new file mode 100644 index 000000000..400bc4829 --- /dev/null +++ b/lib/portus/request_error.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module ::Portus + # RequestError wraps any exception that might arise when performing an HTTP + # request, and provides a common `msg` method. Moreover, all raised exceptions + # will also be logged. + class RequestError < StandardError + # Given an inner exception and a message, it builds up a common error + # message. + def initialize(exception:, message:) + @msg = "#{exception.class.name}: #{message}" + Rails.logger.error @msg + end + + def to_s + @msg + end + end +end diff --git a/lib/portus/security.rb b/lib/portus/security.rb index f2bef8937..f17eefad0 100644 --- a/lib/portus/security.rb +++ b/lib/portus/security.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/security_backends/clair" require "portus/security_backends/dummy" require "portus/security_backends/zypper" diff --git a/lib/portus/security_backends/base.rb b/lib/portus/security_backends/base.rb index 5f82f5b12..af9e896cc 100644 --- a/lib/portus/security_backends/base.rb +++ b/lib/portus/security_backends/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "portus/http_helpers" module Portus diff --git a/lib/portus/security_backends/clair.rb b/lib/portus/security_backends/clair.rb index 136e2dcd3..1d99e40e8 100644 --- a/lib/portus/security_backends/clair.rb +++ b/lib/portus/security_backends/clair.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "portus/security_backends/base" # Docker images contain quite some empty blobs, and trying to upload them will # fail. -EMPTY_LAYER_SHA = "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4".freeze +EMPTY_LAYER_SHA = "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4" module Portus module SecurityBackend @@ -85,7 +87,7 @@ def fetch_layer(digest) # Post the layer pointed by the given index to Clair. def post_layer(index) - parent = index > 0 ? @layers.fetch(index - 1) : "" + parent = index.positive? ? @layers.fetch(index - 1) : "" digest = @layers.fetch(index) uri, req = get_request("/v1/layers", "post") diff --git a/lib/portus/security_backends/dummy.rb b/lib/portus/security_backends/dummy.rb index daca43863..0875d248b 100644 --- a/lib/portus/security_backends/dummy.rb +++ b/lib/portus/security_backends/dummy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: require "portus/security_backends/base" @@ -7,7 +9,7 @@ module SecurityBackend # is meant to be used only for development/testing purposes. class Dummy < ::Portus::SecurityBackend::Base # Files stored in `lib/portus/security_backends/fixtures`. - DUMMY_FIXTURE = "dummy.json".freeze + DUMMY_FIXTURE = "dummy.json" # Whether the response from the `vulnerabilities` method should be as # "Working in Progress". diff --git a/lib/portus/security_backends/zypper.rb b/lib/portus/security_backends/zypper.rb index 1ad2e7a39..73d26d2ba 100644 --- a/lib/portus/security_backends/zypper.rb +++ b/lib/portus/security_backends/zypper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: require "portus/security_backends/base" @@ -36,7 +38,7 @@ def self.config_key def consume_response(response) security = response["Security"] - return [] if security.nil? || security.to_i == 0 + return [] if security.nil? || security.to_i.zero? res = [] response["List"].each do |issue| diff --git a/lib/tasks/annotate.rake b/lib/tasks/annotate.rake index 4c66e7d0e..1717b2c8e 100644 --- a/lib/tasks/annotate.rake +++ b/lib/tasks/annotate.rake @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "annotate" require "portus/db" diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index e2e23bb13..d0925f660 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -1,33 +1,8 @@ +# frozen_string_literal: true + # Tasks taken from Gitlab's yarn.rake and assets.rake files. namespace :portus do - namespace :yarn do - desc "Ensure Yarn is installed" - task :available do - unless system("yarn --version", out: File::NULL) - warn( - "Error: Yarn executable was not detected in the system.", - "Download Yarn at https://yarnpkg.com/en/docs/install" - ) - abort - end - end - - desc "Ensure Node dependencies are installed" - task check: ["yarn:available"] do - cmd = "yarn check --ignore-engines" - cmd += " --offline" if ENV["PACKAGING"] == "yes" - - unless system(cmd, out: File::NULL) - warn( - "Error: You have unmet dependencies. (`yarn check` command failed)", - "Run `yarn install` to install missing modules." - ) - abort - end - end - end - namespace :assets do desc "Compile all frontend assets" task compile: [ diff --git a/lib/tasks/brakeman.rake b/lib/tasks/brakeman.rake index 18afcd65b..bbfe1b1ca 100644 --- a/lib/tasks/brakeman.rake +++ b/lib/tasks/brakeman.rake @@ -1,3 +1,5 @@ +# frozen_string_literal: true + if Rails.env.development? desc "Run Brakeman security checks" task :brakeman do diff --git a/lib/tasks/helpers.rb b/lib/tasks/helpers.rb new file mode 100644 index 000000000..557d58fde --- /dev/null +++ b/lib/tasks/helpers.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +# :nocov: +# rubocop:disable Rails/Exit +# rubocop:disable Rails/Output +module Helpers + # Check that there are the amount of required arguments and they are not blank. + def self.check_arguments!(args, required, optional = 0) + if args.count != required && args.count != required + optional + puts "There are #{required} required arguments" + exit(-1) + end + + args.each do |k, v| + if v.empty? + puts "You have to provide a value for `#{k}'" + exit(-1) + end + end + end + + # Fetch the branch to be picked given the number parameter. + def self.branch(number) + m = number.match(/^(\d+)\.(\d+)./) + "v#{m[1]}.#{m[2]}" + end + + # Check the format as a release number. + def self.check_release_number(number) + return if number.match?(/^(\d)+\.(\d)+\.(\d)+$/) + puts "Version number should follow the format X.Y.Z" + exit(-2) + end + + def self.in?(value, opts) + opts.include?(value.downcase) + end + + # Returns true if the given string value has a value representing a "yes" from + # a y/n option. + def self.yes?(value) + ::Helpers.in?(value, %w[y yes]) + end + + # Returns true if the given string value has a value representing a "no" from + # a y/n option. + def self.no?(value) + ::Helpers.in?(value, %w[n no]) + end + + # Returns true if the given string value has a truthy value. + def self.truthy?(value) + ::Helpers.in?(value, %w[t true]) + end + + # Prints a message until a proper y/n has been given. It returns true if the + # answer was positive, false otherwise. + def self.are_you_sure?(msg) + answer = "" + until ::Helpers.yes(answer) || ::Helpers.no?(answer) + print msg + answer = $stdin.gets.strip + end + + ::Helpers.yes?(answer) + end +end +# rubocop:enable Rails/Exit +# rubocop:enable Rails/Output + +# :nocov: diff --git a/lib/tasks/info.rake b/lib/tasks/info.rake index 2d56fbe8a..d2c9f5257 100644 --- a/lib/tasks/info.rake +++ b/lib/tasks/info.rake @@ -1,3 +1,5 @@ +# frozen_string_literal: true + namespace :portus do desc "Get general info about the running instance" task info: :environment do diff --git a/lib/tasks/man.rake b/lib/tasks/man.rake index 711f62dd4..a130c59d7 100644 --- a/lib/tasks/man.rake +++ b/lib/tasks/man.rake @@ -1,3 +1,5 @@ +# frozen_string_literal: true + if Rails.env.development? || Rails.env.test? require "man_pages" diff --git a/lib/tasks/migrate.rake b/lib/tasks/migrate.rake deleted file mode 100644 index 886560d39..000000000 --- a/lib/tasks/migrate.rake +++ /dev/null @@ -1,58 +0,0 @@ -# :nocov: -namespace :migrate do - # NOTE: this is only available from 2.0.x -> 2.1.x. - # TODO: (mssola) prevent in the future to execute this if the version of - # Portus is higher than 2.1.x. (should be deprecated in 2.2, and removed later - # on). - desc "Update personal namespaces" - task update_personal_namespaces: :environment do - ActiveRecord::Base.transaction do - User.all.find_each do |u| - namespace = Namespace.find_by(name: u.username) - raise "There is no valid personal namespace for #{u.username}!" if namespace.nil? - u.update_attributes(namespace: namespace) - end - end - end - - # NOTE: this is only available from 2.0.x -> 2.1.x. - # TODO: (mssola) prevent in the future to execute this if the version of - # Portus is higher than 2.1.x. (should be deprecated in 2.2, and removed later - # on). - desc "Update LDAP user names" - task update_ldap_names: :environment do - unless APP_CONFIG.enabled?("ldap") - puts "This only applies to LDAP setups..." - exit 0 - end - - puts "Users to be updated:" - count = 0 - User.all.find_each do |u| - if u.ldap_name.present? && u.ldap_name != u.username - puts "- username: #{u.username}\t<=>\tldapname: #{u.ldap_name}" - count += 1 - end - end - - if count.zero? - puts "None. Doing nothing..." - exit 0 - end - - unless ENV["PORTUS_FORCE_LDAP_NAME_UPDATE"] - print "Are you sure that you want to proceed with this ? (y/N) " - opt = $stdin.gets.strip - exit 0 if opt != "y" && opt != "Y" && opt != "yes" - end - - ActiveRecord::Base.transaction do - User.all.find_each do |u| - if u.ldap_name.present? && u.ldap_name != u.username - u.update_attributes!(username: u.ldap_name) - end - end - end - end -end -# :nocov: diff --git a/lib/tasks/portus.rake b/lib/tasks/portus.rake deleted file mode 100644 index 945d7d789..000000000 --- a/lib/tasks/portus.rake +++ /dev/null @@ -1,200 +0,0 @@ -require "pty" - -# Spawn a new command and return its exit status. It will print to stdout on -# real time. -def spawn_cmd(cmd) - status = 0 - - PTY.spawn(cmd) do |stdout, _, pid| - # rubocop:disable Lint/HandleExceptions - begin - stdout.each { |line| print line } - rescue Errno::EIO - # End of output - end - # rubocop:enable Lint/HandleExceptions - - Process.wait(pid) - status = $CHILD_STATUS.exitstatus - end - status -end - -namespace :portus do - desc "Create the account used by Portus to talk with Registry's API" - task create_api_account: :environment do - User.create!( - username: "portus", - password: Rails.application.secrets.portus_password, - email: "portus@portus.com", - admin: true - ) - end - - desc "Create a registry" - task :create_registry, [:name, :hostname, :use_ssl, :external] => :environment do |_, args| - if args.count != 3 && args.count != 4 - puts "There are 3 required arguments and an optional one" - exit(-1) - end - - args.each do |k, v| - if v.empty? && k != :external - puts "You have to provide a value for `#{k}'" - exit(-1) - end - end - - if Registry.any? - puts "There is already a registry configured!" - exit(-1) - end - - registry = Registry.new( - name: args[:name], - hostname: args[:hostname], - use_ssl: args[:use_ssl], - external_hostname: args[:external] - ) - msg = registry.reachable? - unless msg.empty? - puts "\nRegistry not reachable:\n#{registry.inspect}\n#{msg}\n" - exit(-1) - end - registry.save - end - - desc "Create a user" - task :create_user, [:username, :email, :password, :admin] => :environment do |_, args| - if args.count != 4 - puts "There are 4 required arguments" - exit(-1) - end - - args.each do |k, v| - if v.empty? - puts "You have to provide a value for `#{k}'" - exit(-1) - end - end - - unless Registry.any? - puts <<~HERE - - ERROR: There is no registry on the DB! You can either call the portus:create_registry - task, or log in as an administrator into Portus and fill in the form that - will be presented to you. -HERE - exit(-1) - end - - u = User.create!( - username: args["username"], - password: args["password"], - email: args["email"], - admin: args["admin"] - ) - - if u.username != u.namespace.name - puts <<~HERE - - NOTE: the user you just created contained characters that are not accepted for - naming namespaces. Because of this, you've got the following: - - * User name: '#{u.username}' - * Personal namespace: '#{u.namespace.name}' -HERE - end - end - - desc "Give 'admin' role to a user" - task :make_admin, [:username] => [:environment] do |_, args| - unless args[:username] - puts "Specify a username, as in" - puts " rake portus:make_admin[username]" - puts "valid usernames are" - puts User.pluck(:username).to_s - exit(-1) - end - u = User.find_by(username: args[:username]) - if u.nil? - puts "#{args[:username]} not found in database" - puts "valid usernames are" - puts User.pluck(:username).to_s - exit(-2) - end - u.admin = true - u.save - if u.nil? - puts "Sorry something went wrong and I couldn't set this user as admin." - exit(-3) - end - end - - desc "Update the manifest digest of tags" - task :update_tags, [:update] => [:environment] do |_, args| - # Warning - puts <<~HERE - This rake task may take a while depending on how many images have been stored - in your private registry. If you are running this in production it's - recommended that the registry is running in "readonly" mode, so there are no - race conditions with concurrent accesses. - -HERE - - unless ENV["PORTUS_FORCE_DIGEST_UPDATE"] - print "Are you sure that you want to proceed with this ? (y/N) " - opt = $stdin.gets.strip - exit 0 if opt != "y" && opt != "Y" && opt != "yes" - end - - # Fetch the tags to be updated. - update = args[:update] == "true" || args[:update] == "t" - tags = if update - Tag.all - else - Tag.where("tags.digest='' OR tags.image_id=''") - end - - # Some information on the amount of tags to be updated. - if tags.empty? - puts "There are no tags to be updated." - exit 0 - else - puts "Updating a total of #{tags.size} tags..." - end - - # And for each tag fetch its digest and update the DB. - client = Registry.get.client - tags.each_with_index do |t, index| - repo_name = t.repository.name - puts "[#{index + 1}/#{tags.size}] Updating #{repo_name}/#{t.name}" - - begin - id, digest, = client.manifest(t.repository.full_name, t.name) - t.update_attributes(digest: digest, image_id: id) - rescue StandardError => e - puts "Could not get the manifest for #{repo_name}: #{e.message}" - end - end - puts - end - - desc "Properly test Portus" - task :test do |_, args| - tags = args.extras.map { |a| "--tag #{a}" } - tags << "--tag ~integration" if ENV["TRAVIS"] == "true" - - # Run normal tests + integration. - ENV["INTEGRATION_LDAP"] = nil - status = spawn_cmd("rspec spec #{tags.join(" ")}") - exit(status) if status != 0 - exit(0) if ENV["TRAVIS"] == "true" - - # Run LDAP integration tests. - ENV["INTEGRATION_LDAP"] = "t" - tags << "--tag integration" unless args.extras.include?("integration") - status = spawn_cmd("rspec spec #{tags.join(" ")}") - exit(status) - end -end diff --git a/lib/tasks/portus/admin.rake b/lib/tasks/portus/admin.rake new file mode 100644 index 000000000..79995217f --- /dev/null +++ b/lib/tasks/portus/admin.rake @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +namespace :portus do + desc "Give 'admin' role to a user" + task :make_admin, [:username] => [:environment] do |_, args| + unless args[:username] + puts "Specify a username, as in" + puts " rake portus:make_admin[username]" + puts "valid usernames are" + puts User.pluck(:username).to_s + exit(-1) + end + u = User.find_by(username: args[:username]) + if u.nil? + puts "#{args[:username]} not found in database" + puts "valid usernames are" + puts User.pluck(:username).to_s + exit(-2) + end + u.admin = true + u.save + if u.nil? + puts "Sorry something went wrong and I couldn't set this user as admin." + exit(-3) + end + end +end diff --git a/lib/tasks/portus/api.rake b/lib/tasks/portus/api.rake new file mode 100644 index 000000000..d5285ed5d --- /dev/null +++ b/lib/tasks/portus/api.rake @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +namespace :portus do + desc "Create the account used by Portus to talk with Registry's API" + task create_api_account: :environment do + User.create!( + username: "portus", + password: Rails.application.secrets.portus_password, + email: "portus@portus.com", + admin: true + ) + end +end diff --git a/lib/tasks/portus/registry.rake b/lib/tasks/portus/registry.rake new file mode 100644 index 000000000..38e7bf6ea --- /dev/null +++ b/lib/tasks/portus/registry.rake @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative "../helpers" + +namespace :portus do + desc "Create a registry" + task :create_registry, %i[name hostname use_ssl external] => :environment do |_, args| + ::Helpers.check_arguments!(args, 3, 1) + + if Registry.any? + puts "There is already a registry configured!" + exit(-1) + end + + registry = Registry.new( + name: args[:name], + hostname: args[:hostname], + use_ssl: args[:use_ssl], + external_hostname: args[:external] + ) + msg = registry.reachable? + unless msg.empty? + puts "\nRegistry not reachable:\n#{registry.inspect}\n#{msg}\n" + exit(-1) + end + registry.save + end +end diff --git a/lib/tasks/portus/tags.rake b/lib/tasks/portus/tags.rake new file mode 100644 index 000000000..8cc5b4ba8 --- /dev/null +++ b/lib/tasks/portus/tags.rake @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require_relative "../helpers" + +# Returns the tags to be updated. It accepts the `force` argument in which it +# will force the update to all tags. +def tags_to_update(force) + tags = if ::Helpers.truthy?(force) + Tag.all + else + Tag.where("tags.digest='' OR tags.image_id=''") + end + + if tags.empty? + puts "There are no tags to be updated." + exit 0 + else + puts "Updating a total of #{tags.size} tags..." + end + + tags +end + +# Warn the user about the duration of this task and possibly ask whether to exit +# early. +def warn_user! + puts <<~HERE + This rake task may take a while depending on how many images have been stored + in your private registry. If you are running this in production it's + recommended that the registry is running in "readonly" mode, so there are no + race conditions with concurrent accesses. + +HERE + + return if ENV["PORTUS_FORCE_DIGEST_UPDATE"] + + msg = "Are you sure that you want to proceed with this ? (y/n) " + exit 0 unless ::Helpers.are_you_sure?(msg) +end + +namespace :portus do + desc "Update the manifest digest of tags" + task :update_tags, [:update] => [:environment] do |_, args| + warn_user! + + tags = tags_tp_update(args[:update]) + + # And for each tag fetch its digest and update the DB. + client = Registry.get.client + tags.each_with_index do |t, index| + repo_name = t.repository.name + puts "[#{index + 1}/#{tags.size}] Updating #{repo_name}/#{t.name}" + + begin + id, digest, = client.manifest(t.repository.full_name, t.name) + t.update_attributes(digest: digest, image_id: id) + rescue StandardError => e + puts "Could not get the manifest for #{repo_name}: #{e.message}" + end + end + puts + end +end diff --git a/lib/tasks/portus/test.rake b/lib/tasks/portus/test.rake new file mode 100644 index 000000000..13fa0bb47 --- /dev/null +++ b/lib/tasks/portus/test.rake @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require "pty" + +# Spawn a new command and return its exit status. It will print to stdout on +# real time. +def spawn_cmd(cmd) + status = 0 + + PTY.spawn(cmd) do |stdout, _, pid| + begin + stdout.each { |line| print line } + rescue Errno::EIO + puts "EOI" + end + + Process.wait(pid) + status = $CHILD_STATUS.exitstatus + end + status +end + +namespace :portus do + desc "Properly test Portus" + task :test do |_, args| + tags = args.extras.map { |a| "--tag #{a}" } + tags << "--tag ~integration" if ENV["TRAVIS"] == "true" + + # Run normal tests + integration. + ENV["INTEGRATION_LDAP"] = nil + status = spawn_cmd("rspec spec #{tags.join(" ")}") + exit(status) if status != 0 + exit(0) if ENV["TRAVIS"] == "true" + + # Run LDAP integration tests. + ENV["INTEGRATION_LDAP"] = "t" + tags << "--tag integration" unless args.extras.include?("integration") + status = spawn_cmd("rspec spec #{tags.join(" ")}") + exit(status) + end +end diff --git a/lib/tasks/portus/user.rake b/lib/tasks/portus/user.rake new file mode 100644 index 000000000..73e01b29b --- /dev/null +++ b/lib/tasks/portus/user.rake @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require_relative "../helpers" + +# Exits with a proper error message of there is no registry. +def check_registry! + return if Registry.any? + puts <<~HERE + + ERROR: There is no registry on the DB! You can either call the portus:create_registry + task, or log in as an administrator into Portus and fill in the form that + will be presented to you. +HERE + exit(-1) +end + +namespace :portus do + desc "Create a user" + task :create_user, %i[username email password admin] => :environment do |_, args| + # Initial checks. + ::Helpers.check_arguments!(args, 4) + check_registry! + + u = User.create!( + username: args["username"], + password: args["password"], + email: args["email"], + admin: args["admin"] + ) + + # Inform the user if the name of the namespace had to change. + if u.username != u.namespace.name + puts <<~HERE + + NOTE: the user you just created contained characters that are not accepted for + naming namespaces. Because of this, you've got the following: + + * User name: '#{u.username}' + * Personal namespace: '#{u.namespace.name}' +HERE + end + end +end diff --git a/lib/tasks/release.rake b/lib/tasks/release.rake deleted file mode 100644 index 5ed67cb5b..000000000 --- a/lib/tasks/release.rake +++ /dev/null @@ -1,65 +0,0 @@ -namespace :release do - def branch(number) - m = number.match(/^(\d+)\.(\d+)./) - "v#{m[1]}.#{m[2]}" - end - - def check_release_number(number) - return if number.match?(/^(\d)+\.(\d)+\.(\d)+$/) - puts "Version number should follow the format X.Y.Z" - exit(-2) - end - - desc "Prepare new release" - task :prepare, [:number] => :environment do |_, args| - if args.to_hash.empty? - puts "Usage: rake release:prepare[X.Y.Z]" - exit(-1) - end - number = args[:number] - check_release_number(number) - puts "Things you have to do to prepare the release for #{number}" - puts "1- Create new branch #{branch(number)} if it does not exist" - puts "2- Checkout #{branch(number)}" # TODO, what happens if it already exists? - puts "3- Review Gemfile.lock. Review the gem versions." - puts "4- Test and small fixes" - end - - desc "Bump new release" - task :bump, [:number] => :environment do |_, args| - if args.to_hash.empty? - puts "Usage: rake release:push[X.Y.Z]" - exit(-1) - end - number = args[:number] - check_release_number(number) - number =~ /^(\d+)\.(\d+)./ - unless system("git checkout #{branch(number)}") - puts "There was an error checking out #{branch(number)}. Make sure it does exists" - exit(-3) - end - FileUtils.copy("CHANGELOG.md", ".CHANGELOG.md.release.rake") - system("$EDITOR CHANGELOG.md") - changed = FileUtils.identical?("CHANGELOG.md", ".CHANGELOG.md.release.rake") - FileUtils.rm(".CHANGELOG.md.release.rake") - unless changed - answer = "" - until ["yes", "no"].include? answer - puts "CHANGELOG.md unchanged. Are you sure you want to continue?(yes/no)" - answer = gets.strip - end - if answer != "yes" - puts "Ok. See you later" - exit(-4) - end - end - open("VERSION", "w") do |f| - f.write(number) - end - puts "Update VERSION with #{number}" - system("git add VERSION CHANGELOG.md") - system("git commit -m \"Bump version #{number}\"") - system("git tag #{number} -s") - system("git push --tags origin HEAD") - end -end diff --git a/lib/tasks/release/bump.rake b/lib/tasks/release/bump.rake new file mode 100644 index 000000000..c67edac27 --- /dev/null +++ b/lib/tasks/release/bump.rake @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require_relative "../helpers" + +# Returns the number and the branch from the CLI arguments. +def get_branch_from_args(args) + if args.to_hash.empty? + puts "Usage: rake release:push[X.Y.Z]" + exit(-1) + end + + number = args[:number] + ::Helpers.check_release_number(number) + number =~ /^(\d+)\.(\d+)./ + ::Helpers.branch(number) + + [number, branch] +end + +# Checkout the given branch and exit if that was not possible. +def git_checkout(branch) + return if system("git checkout #{branch}") + + puts "There was an error checking out #{branch}. Make sure it does exists" + exit(-3) +end + +namespace :release do + task :bump, [:number] => :environment do |_, args| + number, branch = get_branch_from_args(args) + git_checkout(branch) + + FileUtils.copy("CHANGELOG.md", ".CHANGELOG.md.release.rake") + system("$EDITOR CHANGELOG.md") + changed = FileUtils.identical?("CHANGELOG.md", ".CHANGELOG.md.release.rake") + FileUtils.rm(".CHANGELOG.md.release.rake") + + unless changed + msg = "CHANGELOG.md unchanged. Are you sure you want to continue? (yes/no) " + exit(-4) unless ::Helpers.are_you_sure?(msg) + end + + open("VERSION", "w") { |f| f.write(number) } + + puts "Update VERSION with #{number}" + system("git add VERSION CHANGELOG.md") + system("git commit -m \"Bump version #{number}\"") + system("git tag #{number} -s") + system("git push --tags origin HEAD") + end +end diff --git a/lib/tasks/release/prepare.rake b/lib/tasks/release/prepare.rake new file mode 100644 index 000000000..a19cf3234 --- /dev/null +++ b/lib/tasks/release/prepare.rake @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require_relative "../helpers" + +namespace :release do + desc "Prepare new release" + task :prepare, [:number] => :environment do |_, args| + if args.to_hash.empty? + puts "Usage: rake release:prepare[X.Y.Z]" + exit(-1) + end + + number = args[:number] + ::Helpers.check_release_number(number) + branch = ::Helpers.branch(number) + + puts "Things you have to do to prepare the release for #{number}" + puts "1- Create new branch #{branch} if it does not exist" + puts "2- Checkout #{branch}" # TODO, what happens if it already exists? + puts "3- Review Gemfile.lock. Review the gem versions." + puts "4- Test and small fixes" + end +end diff --git a/lib/tasks/yarn.rake b/lib/tasks/yarn.rake new file mode 100644 index 000000000..1aeb6aee1 --- /dev/null +++ b/lib/tasks/yarn.rake @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +# Tasks taken from Gitlab's yarn.rake and assets.rake files. + +namespace :portus do + namespace :yarn do + desc "Ensure Yarn is installed" + task :available do + unless system("yarn --version", out: File::NULL) + warn( + "Error: Yarn executable was not detected in the system.", + "Download Yarn at https://yarnpkg.com/en/docs/install" + ) + abort + end + end + + desc "Ensure Node dependencies are installed" + task check: ["yarn:available"] do + cmd = "yarn check --ignore-engines" + cmd += " --offline" if ENV["PACKAGING"] == "yes" + + unless system(cmd, out: File::NULL) + warn( + "Error: You have unmet dependencies. (`yarn check` command failed)", + "Run `yarn install` to install missing modules." + ) + abort + end + end + end +end diff --git a/packaging/suse/portusctl/bin/portusctl b/packaging/suse/portusctl/bin/portusctl index 06bf92188..76fd51122 100755 --- a/packaging/suse/portusctl/bin/portusctl +++ b/packaging/suse/portusctl/bin/portusctl @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true require_relative "../lib/portusctl" diff --git a/packaging/suse/portusctl/lib/cli.rb b/packaging/suse/portusctl/lib/cli.rb index d182a9d04..e70852358 100644 --- a/packaging/suse/portusctl/lib/cli.rb +++ b/packaging/suse/portusctl/lib/cli.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: # Class implementing the cli interface of portusctl @@ -9,35 +11,35 @@ class Cli < Thor # SSL certificate options option "ssl-gen-self-signed-certs", - desc: "Generate self-signed certificates", - type: :boolean, - default: false + desc: "Generate self-signed certificates", + type: :boolean, + default: false option "ssl-certs-dir", - desc: "Location of own certificates", - default: "", - long_desc: <<~LONGDESC - Looks for the following required certificate files in the specified folder: - * `/-ca.key`: the certificate key - * `/-ca.crt`: the certificate file + desc: "Location of own certificates", + default: "", + long_desc: <<~LONGDESC + Looks for the following required certificate files in the specified folder: + * `/-ca.key`: the certificate key + * `/-ca.crt`: the certificate file LONGDESC option "ssl-organization", - desc: "SSL certificate: organization", - default: "SUSE Linux GmbH" # gensslcert -o + desc: "SSL certificate: organization", + default: "SUSE Linux GmbH" # gensslcert -o option "ssl-organization-unit", - desc: "SSL certificate: organizational unit", - default: "SUSE Portus example" # gensslcert -u + desc: "SSL certificate: organizational unit", + default: "SUSE Portus example" # gensslcert -u option "ssl-email", - desc: "SSL certificate: email address of webmaster", - default: "kontact-de@novell.com" # gensslcert -e + desc: "SSL certificate: email address of webmaster", + default: "kontact-de@novell.com" # gensslcert -e option "ssl-country", - desc: "SSL certificate: country (two letters)", - default: "DE" # gensslcert -c + desc: "SSL certificate: country (two letters)", + default: "DE" # gensslcert -c option "ssl-city", - desc: "SSL certificate: city", - default: "Nuernberg" # gensslcert -l + desc: "SSL certificate: city", + default: "Nuernberg" # gensslcert -l option "ssl-state", - desc: "SSL certificate: state", - default: "Bayern" # gensslcert -s + desc: "SSL certificate: state", + default: "Bayern" # gensslcert -s # DB options option "db-host", desc: "Database: host", default: "localhost" @@ -54,23 +56,23 @@ class Cli < Thor option "ldap-hostname", desc: "LDAP: server hostname" option "ldap-port", desc: "LDAP: server port", default: "389" option "ldap-method", - desc: "LDAP: encryption method (recommended: starttls)", - default: "plain" + desc: "LDAP: encryption method (recommended: starttls)", + default: "plain" option "ldap-base", desc: "LDAP: base", default: "ou=users, dc=example, dc=com" option "ldap-filter", desc: "LDAP: filter users" option "ldap-uid", desc: "LDAP: uid", default: "uid" option "ldap-authentication-enable", - desc: "LDAP: enable LDAP credentials for user lookup", - type: :boolean, - default: false + desc: "LDAP: enable LDAP credentials for user lookup", + type: :boolean, + default: false option "ldap-authentication-bind-dn", desc: "LDAP: bind DN for authentication" option "ldap-authentication-password", desc: "LDAP: password for authentication" option "ldap-guess-email-enable", - desc: "LDAP: guess email address", - type: :boolean, - default: false + desc: "LDAP: guess email address", + type: :boolean, + default: false option "ldap-guess-email-attr", - desc: "LDAP: attribute to use when guessing email address" + desc: "LDAP: attribute to use when guessing email address" # OAuth require_relative "cli_oauth" @@ -78,124 +80,124 @@ class Cli < Thor # MAILER option "email-from", - desc: "MAIL: sender address", - default: "portus@#{HOSTNAME}" + desc: "MAIL: sender address", + default: "portus@#{HOSTNAME}" option "email-name", desc: "MAIL: sender name", default: "Portus" option "email-reply-to", - desc: "MAIL: reply to address", - default: "no-reply@#{HOSTNAME}" + desc: "MAIL: reply to address", + default: "no-reply@#{HOSTNAME}" option "email-smtp-enable", - desc: "MAIL: use SMTP as the delivery method", - type: :boolean, - default: false + desc: "MAIL: use SMTP as the delivery method", + type: :boolean, + default: false option "email-smtp-address", - desc: "MAIL: the address to the SMTP server", - default: "smtp.example.com" + desc: "MAIL: the address to the SMTP server", + default: "smtp.example.com" option "email-smtp-port", desc: "MAIL: SMTP server port", default: "587" option "email-smtp-username", - desc: "MAIL: the user name to be used for logging in the SMTP server", - default: "username@example.com" + desc: "MAIL: the user name to be used for logging in the SMTP server", + default: "username@example.com" option "email-smtp-password", - desc: "MAIL: the password to be used for logging in the SMTP server", - default: "password" + desc: "MAIL: the password to be used for logging in the SMTP server", + default: "password" option "email-smtp-domain", - desc: "MAIL: the domain of the SMTP server", - default: "example.com" + desc: "MAIL: the domain of the SMTP server", + default: "example.com" # SIGNUP option "signup-enable", - desc: "Enable user signup", - type: :boolean, - default: true + desc: "Enable user signup", + type: :boolean, + default: true # GRAVATAR option "gravatar-enable", - desc: "Enable Gravatar usage", - type: :boolean, - default: true + desc: "Enable Gravatar usage", + type: :boolean, + default: true # JWT EXPIRATION TIME option "jwt-expiration-time", - desc: "Expiration time for the JWT token used by Portus", - type: :numeric, - default: 5 + desc: "Expiration time for the JWT token used by Portus", + type: :numeric, + default: 5 # Catalog pagination option "catalog-page", - desc: "Pagination value for API calls to the registry", - type: :numeric, - default: 100 + desc: "Pagination value for API calls to the registry", + type: :numeric, + default: 100 option "registry-timeout-value", - desc: "Timeout value for API calls to the registry", - type: :numeric, - default: 10 + desc: "Timeout value for API calls to the registry", + type: :numeric, + default: 10 # FIRST USER option "first-user-admin-enable", - desc: "Make the first registered user an admin", - type: :boolean, - default: true + desc: "Make the first registered user an admin", + type: :boolean, + default: true # Display name option "display-name-enable", - desc: "Enable users to set a display name", - type: :boolean, - default: false + desc: "Enable users to set a display name", + type: :boolean, + default: false option "delete-enable", - desc: "Enable delete support. Only do this if your registry is 2.4 or higher", - type: :boolean, - default: false + desc: "Enable delete support. Only do this if your registry is 2.4 or higher", + type: :boolean, + default: false option "change-visibility-enable", - desc: "Allow users to change the visibility of their namespaces", - type: :boolean, - default: true + desc: "Allow users to change the visibility of their namespaces", + type: :boolean, + default: true option "manage-namespace-enable", - desc: "Allow users to modify their namespaces", - type: :boolean, - default: true + desc: "Allow users to modify their namespaces", + type: :boolean, + default: true option "create-namespace-enable", - desc: "Allow users to modify new namespaces", - type: :boolean, - default: true + desc: "Allow users to modify new namespaces", + type: :boolean, + default: true option "manage-team-enable", - desc: "Allow users to modify their teams", - type: :boolean, - default: true + desc: "Allow users to modify their teams", + type: :boolean, + default: true option "create-team-enable", - desc: "Allow users to create new teams", - type: :boolean, - default: true + desc: "Allow users to create new teams", + type: :boolean, + default: true # Security scanning option "security-clair-server", - desc: "The URL allowing Portus to access your CoreOS Clair server", - default: "" + desc: "The URL allowing Portus to access your CoreOS Clair server", + default: "" option "security-clair-health-port", - desc: "The port in which Clair exposes the /health endpoint", - type: :numeric, - default: 6061 + desc: "The port in which Clair exposes the /health endpoint", + type: :numeric, + default: 6061 option "security-zypper-server", - desc: "The URL allowing Portus to access your zypper-docker server", - default: "" + desc: "The URL allowing Portus to access your zypper-docker server", + default: "" option "security-dummy-server", - desc: "If non-empty, then Portus will fake a 'dummy' server (only for development)", - default: "" + desc: "If non-empty, then Portus will fake a 'dummy' server (only for development)", + default: "" # Anonymous browsing option "anonymous-browsing-enable", - desc: "Allow anonymous users to explore public repositories", - type: :boolean, - default: true + desc: "Allow anonymous users to explore public repositories", + type: :boolean, + default: true def setup ensure_root diff --git a/packaging/suse/portusctl/lib/cli_oauth.rb b/packaging/suse/portusctl/lib/cli_oauth.rb index c0a5a6ff6..34cde6b3e 100644 --- a/packaging/suse/portusctl/lib/cli_oauth.rb +++ b/packaging/suse/portusctl/lib/cli_oauth.rb @@ -1,15 +1,19 @@ +# frozen_string_literal: true + module CliOAuth + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/BlockLength def self.included(thor) thor.class_eval do option "oauth-google-oauth2-enable", - desc: "OAuth: Google OAuth2 enable", - type: :boolean, - default: false + desc: "OAuth: Google OAuth2 enable", + type: :boolean, + default: false option "oauth-google-oauth2-id", desc: "OAuth: Google OAuth2 id" option "oauth-google-oauth2-secret", desc: "OAuth: Google OAuth2 secret" option "oauth-google-oauth2-domain", desc: "OAuth: Google OAuth2 email's domain restriction" option "oauth-google-oauth2-options-hd", - desc: "OAuth: Google OAuth2 group (GSute) restriction" + desc: "OAuth: Google OAuth2 group (GSute) restriction" option "oauth-open-id-enable", desc: "OAuth: Open ID enable", type: :boolean, default: false option "oauth-open-id-identifier", desc: "OAuth: Open ID identifier" option "oauth-open-id-domain", desc: "OAuth: Open ID email's domain restriction" @@ -26,11 +30,13 @@ def self.included(thor) option "oauth-gitlab-domain", desc: "OAuth: Gitlab email's domain restriction" option "oauth-gitlab-server", desc: "OAuth: Gitlab server" option "oauth-bitbucket-enable", - desc: "OAuth: Bitbucket enable", type: :boolean, default: false + desc: "OAuth: Bitbucket enable", type: :boolean, default: false option "oauth-bitbucket-key", desc: "OAuth: Bitbucket key" option "oauth-bitbucket-secret", desc: "OAuth: Bitbucket secret" option "oauth-bitbucket-domain", desc: "OAuth: Bitbucket domain restriction" option "oauth-bitbucket-options-team", desc: "OAuth: Bitbucket team restriction" end end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/BlockLength end diff --git a/packaging/suse/portusctl/lib/configurator.rb b/packaging/suse/portusctl/lib/configurator.rb index 3262dec18..19e571186 100644 --- a/packaging/suse/portusctl/lib/configurator.rb +++ b/packaging/suse/portusctl/lib/configurator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: require_relative "registry" @@ -36,6 +38,7 @@ def apache # * create the ssl certificates if specified # * check the presence of the required files # * copy the certificates to the right locations + # rubocop:disable Metrics/MethodLength def ssl if @options["ssl-gen-self-signed-certs"] puts "Generating private key and certificate" @@ -87,6 +90,7 @@ def ssl ) Runner.exec("update-ca-certificates") end + # rubocop:enable Metrics/MethodLength # Creates the database.yml file required by Rails. Note that this method will # wipe out any previous contents. @@ -101,6 +105,7 @@ def database_config end # Creates the database and performs the migrations + # rubocop:disable Metrics/MethodLength def create_database if dockerized? puts "Running inside of a docker container" @@ -132,6 +137,7 @@ def create_database # rubocop:enable Lint/RescueWithoutErrorClass FileUtils.chown_R("wwwrun", "www", "/srv/Portus/tmp") end + # rubocop:enable Metrics/MethodLength # Creates the config-local.yml file used by Portus def config_local diff --git a/packaging/suse/portusctl/lib/constants.rb b/packaging/suse/portusctl/lib/constants.rb index 66e7ef11d..b0a93db7a 100644 --- a/packaging/suse/portusctl/lib/constants.rb +++ b/packaging/suse/portusctl/lib/constants.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Some useful constants used by portus # Checks whether it's running inside of a Docker container or not @@ -9,4 +11,4 @@ def dockerized? # See packaging/suse/bin/portusctl BUNDLER_BIN = ENV["BUNDLER_BIN"] HOSTNAME = (dockerized? || ENV["TRAVIS"] ? `hostname -f` : `hostnamectl --static status`).chomp -PORTUS_ROOT = "/srv/Portus".freeze +PORTUS_ROOT = "/srv/Portus" diff --git a/packaging/suse/portusctl/lib/helper.rb b/packaging/suse/portusctl/lib/helper.rb index f02403995..eb731edac 100644 --- a/packaging/suse/portusctl/lib/helper.rb +++ b/packaging/suse/portusctl/lib/helper.rb @@ -1,15 +1,15 @@ +# frozen_string_literal: true + # :nocov: def check_setup_flags(options) - if options["ssl-gen-self-signed-certs"] && \ - !options["ssl-certs-dir"].chomp.empty? + if options["ssl-gen-self-signed-certs"] && !options["ssl-certs-dir"].chomp.empty? warn "cannot use both options --ssl-gen-self-signed-certs and " \ "--ssl-certs-dir at the same time" exit 1 end - return unless options["ldap-enable"] && \ - options["ldap-hostname"].blank? + return unless options["ldap-enable"] && options["ldap-hostname"].blank? warn "LDAP support is enabled but you didn't specify a value for ldap-hostname" exit 1 diff --git a/packaging/suse/portusctl/lib/portusctl.rb b/packaging/suse/portusctl/lib/portusctl.rb index 9dbdc67d3..16679e175 100644 --- a/packaging/suse/portusctl/lib/portusctl.rb +++ b/packaging/suse/portusctl/lib/portusctl.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "erb" require "fileutils" require "securerandom" diff --git a/packaging/suse/portusctl/lib/registry.rb b/packaging/suse/portusctl/lib/registry.rb index 4f951aa2b..76900287e 100644 --- a/packaging/suse/portusctl/lib/registry.rb +++ b/packaging/suse/portusctl/lib/registry.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: module Portusctl # Contains all the needed methods for configuring the registry. You should @@ -28,7 +30,7 @@ def registry protected - REGISTRY_RPM = "docker-distribution-registry".freeze + REGISTRY_RPM = "docker-distribution-registry" ZYPPER_NOT_INSTALLED = 104 # ZYPPER_EXIT_INF_CAP_NOT_FOUND # Checks whether the Docker Distribution package is already installed in the diff --git a/packaging/suse/portusctl/lib/runner.rb b/packaging/suse/portusctl/lib/runner.rb index b17d9cb70..3fdd9cff1 100644 --- a/packaging/suse/portusctl/lib/runner.rb +++ b/packaging/suse/portusctl/lib/runner.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: # Helper file used to run external commands diff --git a/packaging/suse/portusctl/lib/template_writer.rb b/packaging/suse/portusctl/lib/template_writer.rb index 27b985517..c6e5f0576 100644 --- a/packaging/suse/portusctl/lib/template_writer.rb +++ b/packaging/suse/portusctl/lib/template_writer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # :nocov: # Class taking care of processing the template files used by @@ -23,7 +25,7 @@ def self.render(template_name, context) def self.load_template(template_name) t = File.join( File.expand_path("../../templates", __FILE__), - template_name + template_name ) File.read(t) end diff --git a/packaging/suse/portusctl/spec/man_spec.rb b/packaging/suse/portusctl/spec/man_spec.rb index aad969c00..6712b9dd8 100644 --- a/packaging/suse/portusctl/spec/man_spec.rb +++ b/packaging/suse/portusctl/spec/man_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "spec_helper" require "man_pages" @@ -25,9 +27,10 @@ def names(main = true) files << "portusctl" end +# rubocop:disable Metrics/BlockLength describe ManPages do it "describes all the available commands" do - names.each { |c| expect(File.exist?(md_path(c))).to be_truthy } + names.each { |c| expect(File).to be_exist(md_path(c)) } end it "contains the right header/footer" do @@ -36,7 +39,7 @@ def names(main = true) end it "is up-to-date md to man" do - mp = ManPages.new + mp = described_class.new names.each do |n| got = mp.render_markdown(md_path(n)) @@ -48,9 +51,9 @@ def names(main = true) end it "contains all the required sections" do - common = ["NAME", "SYNOPSIS", "DESCRIPTION", "HISTORY"] + common = %w[NAME SYNOPSIS DESCRIPTION HISTORY] - (common + ["COMMANDS", "EXAMPLES"]).each do |section| + (common + %w[COMMANDS EXAMPLES]).each do |section| expect(section_in_file(section, "portusctl")).to be_truthy end @@ -59,7 +62,7 @@ def names(main = true) if ["portusctl-logs", "portusctl-help", "portusctl-make-admin"].include?(n) common elsif n == "portusctl-setup" - common + ["OPTIONS", "EXAMPLES"] + common + %w[OPTIONS EXAMPLES] else common + ["EXAMPLES"] end @@ -79,3 +82,4 @@ def names(main = true) end end end +# rubocop:enable Metrics/BlockLength diff --git a/packaging/suse/portusctl/spec/options_spec.rb b/packaging/suse/portusctl/spec/options_spec.rb index d63568f3b..90d09535d 100644 --- a/packaging/suse/portusctl/spec/options_spec.rb +++ b/packaging/suse/portusctl/spec/options_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "spec_helper" require "yaml" @@ -44,7 +46,7 @@ def get_keys(hsh, prefix = "") # setup command. config_keys = get_keys(yml).map { |k| format_key(k) } config_keys.delete("machine-fqdn-value") - setup_keys = Cli.commands["setup"].options.keys + setup_keys = described_class.commands["setup"].options.keys diff = config_keys - (config_keys & setup_keys) raw = "The following keys are available in the config but not in the setup command: " @@ -54,6 +56,6 @@ def get_keys(hsh, prefix = "") it "returns the proper name of the given flag" do argv = ["--flag"] - expect { Cli.start(argv) }.to output("Unknown switches '--flag'\n").to_stderr + expect { described_class.start(argv) }.to output("Unknown switches '--flag'\n").to_stderr end end diff --git a/packaging/suse/portusctl/spec/registry_spec.rb b/packaging/suse/portusctl/spec/registry_spec.rb index e59ab3c66..1a3e8ff99 100644 --- a/packaging/suse/portusctl/spec/registry_spec.rb +++ b/packaging/suse/portusctl/spec/registry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "spec_helper" class Klass @@ -27,10 +29,11 @@ def self.safe_exec_test(_cmd, _args = []) end end +# rubocop:disable Metrics/BlockLength describe Portusctl::Registry do let(:klass) { Klass.new } - before :each do + before do ENV["TEST_CONFIRM"] = nil ENV["TEST_EXIT_STATUS"] = nil ENV["PORTUSCTL_FORCE"] = nil @@ -41,7 +44,7 @@ def self.safe_exec_test(_cmd, _args = []) context "PORTUSCTL_FORCE has been set" do it "returns true if the package already exists" do ENV["PORTUSCTL_FORCE"] = "t" - expect(klass.registry_local_test?).to be_truthy + expect(klass).to be_registry_local_test end it "installs the RPM" do @@ -55,25 +58,24 @@ def self.safe_exec_test(_cmd, _args = []) context "Manual execution" do it "returns true if the package exists and the user wants to overwrite the config" do - ENV["TEST_CONFIRM"] = "y" - expect(klass.registry_local_test?).to be_truthy + expect(klass).to be_registry_local_test ENV["TEST_CONFIRM"] = "n" - expect(klass.registry_local_test?).to be_falsey + expect(klass).not_to be_registry_local_test end it "returns false if `zypper se` failed for an unknown reason" do ENV["TEST_EXIT_STATUS"] = "1" - expect(klass.registry_local_test?).to be_falsey + expect(klass).not_to be_registry_local_test end it "calls `registry_safe_install!` if the package has not been installed" do ENV["TEST_EXIT_STATUS"] = "104" allow_any_instance_of(Klass).to receive(:registry_safe_install!).and_return(true) - expect(klass.registry_local_test?).to be_truthy + expect(klass).to be_registry_local_test end it "installs the rpm if confirmation was given" do @@ -95,3 +97,4 @@ def self.safe_exec_test(_cmd, _args = []) end end end +# rubocop:enable Metrics/BlockLength diff --git a/packaging/suse/portusctl/spec/spec_helper.rb b/packaging/suse/portusctl/spec/spec_helper.rb index 1d3fd03a5..2522809a4 100644 --- a/packaging/suse/portusctl/spec/spec_helper.rb +++ b/packaging/suse/portusctl/spec/spec_helper.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + require_relative "../lib/portusctl" diff --git a/spec/api/grape_api/v1/health_spec.rb b/spec/api/grape_api/v1/health_spec.rb index 0488a0143..394b193c6 100644 --- a/spec/api/grape_api/v1/health_spec.rb +++ b/spec/api/grape_api/v1/health_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" # Helper for the tests on the database that simply calls :health and returns the @@ -61,7 +63,7 @@ def db_helper_msg end describe "Clair enabled" do - before :each do + before do APP_CONFIG["security"]["clair"]["server"] = "http://registry.mssola.cat" APP_CONFIG["security"]["clair"]["health_port"] = "6061" create(:registry, hostname: "registry.mssola.cat", use_ssl: true) diff --git a/spec/api/grape_api/v1/namespaces_spec.rb b/spec/api/grape_api/v1/namespaces_spec.rb index 7e76d058a..2f03bc6bd 100644 --- a/spec/api/grape_api/v1/namespaces_spec.rb +++ b/spec/api/grape_api/v1/namespaces_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe API::V1::Namespaces do @@ -25,7 +27,7 @@ viewers: [viewer]) end - before :each do + before do @admin_header = build_token_header(admin_token) @owner_header = build_token_header(owner_token) @contributor_header = build_token_header(contributor_token) diff --git a/spec/api/grape_api/v1/registries_spec.rb b/spec/api/grape_api/v1/registries_spec.rb index 8e6bf002e..227901d0b 100644 --- a/spec/api/grape_api/v1/registries_spec.rb +++ b/spec/api/grape_api/v1/registries_spec.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require "rails_helper" describe API::V1::Registries do - before :each do + before do admin = create :admin token = create :application_token, user: admin @header = build_token_header(token) diff --git a/spec/api/grape_api/v1/repositories_spec.rb b/spec/api/grape_api/v1/repositories_spec.rb index 0fa850351..291abb4e3 100644 --- a/spec/api/grape_api/v1/repositories_spec.rb +++ b/spec/api/grape_api/v1/repositories_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe API::V1::Repositories do @@ -9,7 +11,7 @@ team: create(:team)) end - before :each do + before do @header = build_token_header(token) end diff --git a/spec/api/grape_api/v1/root_spec.rb b/spec/api/grape_api/v1/root_spec.rb index 1af9a2899..e800aa714 100644 --- a/spec/api/grape_api/v1/root_spec.rb +++ b/spec/api/grape_api/v1/root_spec.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" +# TestAPI implements a MethodNotAllowed endpoint. class TestAPI < Grape::API version "v1", using: :path @@ -8,9 +11,11 @@ class TestAPI < Grape::API end end +# Re-opening ::API::RootAPI to mount the TestAPI endpoints. class ::API::RootAPI mount ::TestAPI end +# rubocop:enable Style/ClassAndModuleChildren describe API::RootAPI do it "handles unknown routes" do diff --git a/spec/api/grape_api/v1/tags_spec.rb b/spec/api/grape_api/v1/tags_spec.rb index f1ff99fcd..3b347348f 100644 --- a/spec/api/grape_api/v1/tags_spec.rb +++ b/spec/api/grape_api/v1/tags_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe API::V1::Tags do @@ -10,7 +12,7 @@ end let!(:repository) { create(:repository, namespace: public_namespace) } - before :each do + before do @header = build_token_header(token) end diff --git a/spec/api/grape_api/v1/teams_spec.rb b/spec/api/grape_api/v1/teams_spec.rb index d75d328af..1b40d2588 100644 --- a/spec/api/grape_api/v1/teams_spec.rb +++ b/spec/api/grape_api/v1/teams_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe API::V1::Teams do @@ -11,7 +13,7 @@ hidden: true) end - before :each do + before do @header = build_token_header(token) @user_header = build_token_header(user_token) end diff --git a/spec/api/grape_api/v1/users_spec.rb b/spec/api/grape_api/v1/users_spec.rb index bb73fd087..0e3e525c9 100644 --- a/spec/api/grape_api/v1/users_spec.rb +++ b/spec/api/grape_api/v1/users_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe API::V1::Users do @@ -10,7 +12,7 @@ } end - before :each do + before do admin = create :admin token = create :application_token, user: admin @header = build_token_header(token) @@ -83,7 +85,7 @@ context "with invalid params" do it "returns errors" do post "/api/v1/users", { user: { username: "", email: "", password: "" } }, - @header + @header expect(response).to have_http_status(:bad_request) expect(JSON.parse(response.body)["errors"]).not_to be_nil end @@ -116,7 +118,7 @@ it "updates user but not display_name" do user = create :user, display_name: "John Smith" put "/api/v1/users/#{user.id}", { user: user_data.except(:display_name) }, - @header + @header expect(response).to have_http_status(:success) expect(User.find(user.id).display_name).to eq user.display_name end @@ -127,7 +129,7 @@ user = create :user user2 = create :user put "/api/v1/users/#{user.id}", { user: { username: user2.username } }, - @header + @header expect(response).to have_http_status(:bad_request) expect(JSON.parse(response.body)["errors"]).not_to be_nil end @@ -176,7 +178,7 @@ it "creates user's token" do user = create :user post "/api/v1/users/#{user.id}/application_tokens", \ - { application: "test" }, @header + { application: "test" }, @header expect(response).to have_http_status(:success) expect(ApplicationToken.count).to eq 2 expect(JSON.parse(response.body)).not_to be_nil @@ -185,7 +187,7 @@ it "returns errors" do token = create :application_token post "/api/v1/users/#{token.user_id}/application_tokens", \ - { application: token.application }, @header + { application: token.application }, @header expect(response).to have_http_status(:bad_request) expect(JSON.parse(response.body)["errors"]).not_to be_nil end @@ -193,7 +195,7 @@ it "returns server error" do token = create :application_token post "/api/v1/users/#{token.user_id}/application_tokens", - { application: nil }, @header + { application: nil }, @header expect(response).to have_http_status(:internal_server_error) end end diff --git a/spec/api/grape_api/v1/version_spec.rb b/spec/api/grape_api/v1/version_spec.rb index d0f83d00f..9d1afe7ed 100644 --- a/spec/api/grape_api/v1/version_spec.rb +++ b/spec/api/grape_api/v1/version_spec.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + require "rails_helper" describe API::Version do let!(:admin) { create(:admin) } let!(:token) { create(:application_token, user: admin) } - before :each do + before do @header = build_token_header(token) end @@ -17,7 +19,7 @@ resp = JSON.parse(response.body) expect(resp["api-versions"]).to eq(["v1"]) expect(resp["version"]).to eq(::Version.from_file) - expect(resp["git"]).to_not include("tag") + expect(resp["git"]).not_to include("tag") end it "returns the tag when present" do diff --git a/spec/api/v2/events_spec.rb b/spec/api/v2/events_spec.rb index 957a9f383..6cac03b31 100644 --- a/spec/api/v2/events_spec.rb +++ b/spec/api/v2/events_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "/v2/token" do diff --git a/spec/api/v2/ping_spec.rb b/spec/api/v2/ping_spec.rb index cf30b707f..c004b9b98 100644 --- a/spec/api/v2/ping_spec.rb +++ b/spec/api/v2/ping_spec.rb @@ -1,7 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" describe "/v2 ping" do - let(:auth_mech) { ActionController::HttpAuthentication::Basic } let(:password) { "this is a test" } let(:user) { create(:user, password: password) } @@ -22,5 +23,4 @@ get v2_ping_url, { service: "test", account: "account" }, invalid_auth_header expect(response.status).to eq 401 end - end diff --git a/spec/api/v2/token_spec.rb b/spec/api/v2/token_spec.rb index f4c4acf44..578c788f1 100644 --- a/spec/api/v2/token_spec.rb +++ b/spec/api/v2/token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "/v2/token" do @@ -32,22 +34,23 @@ def parse_token(body) scope: "repository:foo_namespace/me:push" } end + before do create(:namespace, name: "foo_namespace", registry: registry) end it "denies access when the password is wrong" do get v2_token_url, - valid_request, - invalid_auth_header + valid_request, + invalid_auth_header expect(response.status).to eq 401 end it "denies access when the user does not exist" do get v2_token_url, - valid_request, - nonexistent_auth_header + valid_request, + nonexistent_auth_header expect(response.status).to eq 401 end @@ -74,12 +77,12 @@ def parse_token(body) ) get v2_token_url, - { - service: registry.hostname, - account: user.username, - scope: "repository:#{user.username}/busybox:push,pull" - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, token_plain) + { + service: registry.hostname, + account: user.username, + scope: "repository:#{user.username}/busybox:push,pull" + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, token_plain) expect(response.status).to eq 200 end @@ -93,12 +96,12 @@ def parse_token(body) ) get v2_token_url, - { - service: registry.hostname, - account: user.username, - scope: "repository:#{user.username}/busybox:push,pull" - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, "wrong") + { + service: registry.hostname, + account: user.username, + scope: "repository:#{user.username}/busybox:push,pull" + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, "wrong") expect(response.status).to eq 401 end @@ -110,12 +113,12 @@ def parse_token(body) it "does not allow to pull a private namespace from another team" do # It works for the regular user get v2_token_url, - { - service: registry.hostname, - account: user.username, - scope: "repository:#{user.username}/busybox:push,pull" - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, password) + { + service: registry.hostname, + account: user.username, + scope: "repository:#{user.username}/busybox:push,pull" + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, password) expect(response.status).to eq 200 payload = parse_token response.body @@ -123,12 +126,12 @@ def parse_token(body) # But not for another get v2_token_url, - { - service: registry.hostname, - account: another.username, - scope: "repository:#{user.username}/busybox:push,pull" - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(another.username, password) + { + service: registry.hostname, + account: another.username, + scope: "repository:#{user.username}/busybox:push,pull" + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(another.username, password) expect(response.status).to eq 200 payload = parse_token response.body @@ -140,12 +143,12 @@ def parse_token(body) # It works for the regular user get v2_token_url, - { - service: registry.hostname, - account: user.username, - scope: scope - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, password) + { + service: registry.hostname, + account: user.username, + scope: scope + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(user.username, password) expect(response.status).to eq 200 payload = parse_token response.body @@ -153,12 +156,12 @@ def parse_token(body) # But not for another get v2_token_url, - { - service: registry.hostname, - account: another.username, - scope: scope - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(another.username, password) + { + service: registry.hostname, + account: another.username, + scope: scope + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials(another.username, password) expect(response.status).to eq 200 payload = parse_token response.body @@ -167,7 +170,7 @@ def parse_token(body) end context "as LDAP user I can authenticate from Docker CLI" do - before :each do + before do APP_CONFIG["ldap"] = { "enabled" => true, "base" => "" } allow_any_instance_of(Portus::LDAP).to receive(:authenticate!).and_call_original allow_any_instance_of(Net::LDAP).to receive(:bind_as).and_return(true) @@ -175,11 +178,11 @@ def parse_token(body) it "authenticates if the HTTP Basic Authentication was given" do get v2_token_url, - { - service: registry.hostname, - account: "ldapuser" - }, - "HTTP_AUTHORIZATION" => auth_mech.encode_credentials("ldapuser", "12341234") + { + service: registry.hostname, + account: "ldapuser" + }, + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials("ldapuser", "12341234") expect(response.status).to eq 200 @@ -231,16 +234,15 @@ def parse_token(body) it "decoded payload should not contain access key" do payload = parse_token response.body - expect(payload).to_not have_key("access") + expect(payload).not_to have_key("access") end - end context "unknown scope requested" do before do get v2_token_url, - { service: registry.hostname, account: "account", scope: "whale:foo,bar" }, - valid_auth_header + { service: registry.hostname, account: "account", scope: "whale:foo,bar" }, + valid_auth_header end it "respond with 401" do @@ -257,12 +259,12 @@ def parse_token(body) .with(personal_namespace, :pull?) get v2_token_url, - { - service: registry.hostname, - account: user.username, - scope: "repository:#{user.username}/busybox:push,pull" - }, - valid_auth_header + { + service: registry.hostname, + account: user.username, + scope: "repository:#{user.username}/busybox:push,pull" + }, + valid_auth_header end it "allows to pull an image in which this user is just a viewer" do @@ -271,9 +273,9 @@ def parse_token(body) allow_any_instance_of(NamespacePolicy).to receive(:pull?).and_return(true) get v2_token_url, - { service: registry.hostname, account: user.username, - scope: "repository:#{user.username}/busybox:push,pull" }, - valid_auth_header + { service: registry.hostname, account: user.username, + scope: "repository:#{user.username}/busybox:push,pull" }, + valid_auth_header expect(response.status).to eq 200 @@ -294,10 +296,9 @@ def parse_token(body) end let(:valid_portus_auth_header) do + pass = Rails.application.secrets.portus_password { - "HTTP_AUTHORIZATION" => - auth_mech.encode_credentials("portus", - Rails.application.secrets.portus_password) + "HTTP_AUTHORIZATION" => auth_mech.encode_credentials("portus", pass) } end @@ -348,8 +349,7 @@ def parse_token(body) expect(response.status).to eq 200 payload = parse_token response.body expect(payload["access"].size).to eq(1) - expect(payload["access"][0]["actions"]).to eq(["push", "pull"]) - + expect(payload["access"][0]["actions"]).to eq(%w[push pull]) end end @@ -373,7 +373,7 @@ def parse_token(body) end context "reposity scope" do - it "it responds with 200 and no access" do + it "responds with 200 and no access" do # force creation of the namespace namespace = create(:namespace, team: Team.find_by(name: user.username), @@ -395,9 +395,6 @@ def parse_token(body) end end end - end - end - end diff --git a/spec/controllers/admin/activities_controller_spec.rb b/spec/controllers/admin/activities_controller_spec.rb index 4e34f29fe..48bcc8d66 100644 --- a/spec/controllers/admin/activities_controller_spec.rb +++ b/spec/controllers/admin/activities_controller_spec.rb @@ -1,14 +1,16 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe Admin::ActivitiesController, type: :controller do let(:admin) { create(:admin) } - before :each do + before do sign_in admin end describe "GET #index" do - before :each do + before do create(:registry) end @@ -46,7 +48,7 @@ let(:global_repository) { create(:repository, name: "sles11sp3", namespace: global_namespace) } let(:global_tag) { create(:tag, name: "1.0.0", repository: global_repository) } - before :each do + before do Timecop.travel(Time.gm(2015, 1, 1)) create(:activity_team_create, trackable_id: team.id, @@ -135,7 +137,7 @@ it "generates an CSV file with all the entries" do # Create activities way beyond a single page. - Array.new(50) { rand(1000..10000) }.uniq.each do |nr| + Array.new(50) { rand(1000..10_000) }.uniq.each do |nr| team = Team.new(name: "team#{nr}") team.owners << user team.save diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb index 21b24c36d..ff60aed54 100644 --- a/spec/controllers/admin/dashboard_controller_spec.rb +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe Admin::DashboardController, type: :controller do @@ -5,7 +7,7 @@ let(:user) { create(:user) } context "as admin user" do - before :each do + before do sign_in admin end @@ -33,7 +35,7 @@ end context "as normal user" do - before :each do + before do sign_in user end diff --git a/spec/controllers/admin/namespaces_controller_spec.rb b/spec/controllers/admin/namespaces_controller_spec.rb index 04cbccf5c..03b439e28 100644 --- a/spec/controllers/admin/namespaces_controller_spec.rb +++ b/spec/controllers/admin/namespaces_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe Admin::NamespacesController, type: :controller do @@ -5,7 +7,7 @@ let(:user) { create(:user) } context "as admin user" do - before :each do + before do create(:registry) sign_in admin end @@ -62,7 +64,7 @@ end context "as normal user" do - before :each do + before do sign_in user end diff --git a/spec/controllers/admin/registries_controller_spec.rb b/spec/controllers/admin/registries_controller_spec.rb index 59a94fff9..01c3ab71c 100644 --- a/spec/controllers/admin/registries_controller_spec.rb +++ b/spec/controllers/admin/registries_controller_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe Admin::RegistriesController, type: :controller do let(:admin) { create(:admin) } - before :each do + before do sign_in admin end diff --git a/spec/controllers/admin/teams_controller_spec.rb b/spec/controllers/admin/teams_controller_spec.rb index e27e4fa75..360baee93 100644 --- a/spec/controllers/admin/teams_controller_spec.rb +++ b/spec/controllers/admin/teams_controller_spec.rb @@ -1,12 +1,13 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe Admin::TeamsController, type: :controller do - let(:admin) { create(:admin) } let(:user) { create(:user) } context "as admin user" do - before :each do + before do create(:registry) sign_in admin end @@ -34,7 +35,7 @@ end context "as normal user" do - before :each do + before do sign_in user end @@ -45,5 +46,4 @@ end end end - end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 47d6114eb..24346721e 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe Admin::UsersController, type: :controller do @@ -5,7 +7,7 @@ let(:user) { create(:user) } context "as admin user" do - before :each do + before do create(:registry) sign_in admin end @@ -33,7 +35,7 @@ end context "as normal user" do - before :each do + before do sign_in user end @@ -46,7 +48,7 @@ end context "PUT toggle admin" do - before :each do + before do create(:registry) sign_in admin end @@ -69,7 +71,7 @@ end describe "GET #new" do - before :each do + before do create(:registry) sign_in admin end @@ -81,7 +83,7 @@ end describe "POST #create" do - before :each do + before do create(:registry) sign_in admin end @@ -110,7 +112,7 @@ end describe "GET #edit" do - before :each do + before do create(:registry) sign_in admin end @@ -127,7 +129,7 @@ end describe "PUT/PATCH #update" do - before :each do + before do create(:registry) sign_in admin end @@ -157,7 +159,7 @@ end describe "DELETE #destroy" do - before :each do + before do create(:registry) sign_in admin end diff --git a/spec/controllers/api/base_controller_spec.rb b/spec/controllers/api/base_controller_spec.rb index 1702ab67b..59a24b64f 100644 --- a/spec/controllers/api/base_controller_spec.rb +++ b/spec/controllers/api/base_controller_spec.rb @@ -1,9 +1,9 @@ +# frozen_string_literal: true + require "rails_helper" describe Api::BaseController do - controller do - def ping1 raise Api::BaseController::ScopeNotHandled end @@ -11,7 +11,6 @@ def ping1 def ping2 raise Namespace::AuthScope::ResourceIsNotFound end - end before do @@ -22,13 +21,10 @@ def ping2 end describe ".?deny_access" do - it "outputs empty body with 401 response status" do get :ping1 expect(response.status).to eq 401 expect(response.body).to be_empty end - end - end diff --git a/spec/controllers/api/v2/ping_controller_spec.rb b/spec/controllers/api/v2/ping_controller_spec.rb index 97342fc3e..034133a37 100644 --- a/spec/controllers/api/v2/ping_controller_spec.rb +++ b/spec/controllers/api/v2/ping_controller_spec.rb @@ -1,19 +1,15 @@ +# frozen_string_literal: true + require "rails_helper" describe Api::V2::PingController do - describe "#ping" do - context "user authorized" do - it "responds with 200" do sign_in(create(:user)) get :ping expect(response.status).to eq 200 end - end - end - end diff --git a/spec/controllers/application_tokens_controller_spec.rb b/spec/controllers/application_tokens_controller_spec.rb index 89aa14e42..42ad25f60 100644 --- a/spec/controllers/application_tokens_controller_spec.rb +++ b/spec/controllers/application_tokens_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: application_tokens @@ -20,7 +22,7 @@ let(:application) { "test application" } describe "POST #create" do - before :each do + before do sign_in user end @@ -48,11 +50,10 @@ expect(response.status).to be 422 end - end describe "DELETE #destroy" do - before :each do + before do sign_in user end diff --git a/spec/controllers/auth/omniauth_callbacks_controller_spec.rb b/spec/controllers/auth/omniauth_callbacks_controller_spec.rb index 27977069b..a88c77c00 100644 --- a/spec/controllers/auth/omniauth_callbacks_controller_spec.rb +++ b/spec/controllers/auth/omniauth_callbacks_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe Auth::OmniauthCallbacksController do @@ -14,16 +16,16 @@ it "redirect to /users/sign_in" do get :google_oauth2 expect(response).to redirect_to new_user_session_url - expect(subject.current_user).to eql nil + expect(subject.current_user).to be nil end end context "when got data from provider," do before do OmniAuth.config.add_mock(:google_oauth2, - provider: "google_oauth2", - uid: "12345", - info: { email: "test@mail.net" }) + provider: "google_oauth2", + uid: "12345", + info: { email: "test@mail.net" }) request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:google_oauth2] end @@ -37,7 +39,7 @@ create :user, email: "test@mail.net" get :google_oauth2 expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eq(nil) + expect(subject.current_user).not_to eq(nil) end end @@ -52,7 +54,7 @@ APP_CONFIG["oauth"]["google_oauth2"]["domain"] = "domain.net" get :google_oauth2 expect(response).to redirect_to new_user_session_url - expect(subject.current_user).to eql nil + expect(subject.current_user).to be nil end end end @@ -62,9 +64,9 @@ before do APP_CONFIG["oauth"] = { "open_id" => { "domain" => "" } } OmniAuth.config.add_mock(:open_id, - provider: "open_id", - uid: "12345", - info: { email: "test@mail.net" }) + provider: "open_id", + uid: "12345", + info: { email: "test@mail.net" }) request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:open_id] end @@ -72,7 +74,7 @@ create :user, email: "test@mail.net" get :open_id expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eq(nil) + expect(subject.current_user).not_to eq(nil) end end @@ -85,10 +87,10 @@ } } OmniAuth.config.add_mock(:github, - provider: "github", - uid: "12345", - credentials: { token: "1234567890" }, - info: { email: "test@mail.net" }) + provider: "github", + uid: "12345", + credentials: { token: "1234567890" }, + info: { email: "test@mail.net" }) request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:github] create :user, email: "test@mail.net" end @@ -96,7 +98,7 @@ it "with team and organization aren't setted, sign in and redirect to /" do get :github expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eql nil + expect(subject.current_user).not_to eql nil end context "with organization is setted and team isn't setted," do @@ -106,7 +108,7 @@ get :github end expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eql nil + expect(subject.current_user).not_to eql nil end it "when organization doesn't match, redirect to /users/sign_in" do @@ -115,7 +117,7 @@ get :github end expect(response).to redirect_to new_user_session_url - expect(subject.current_user).to eql nil + expect(subject.current_user).to be nil end end @@ -127,7 +129,7 @@ get :github end expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eql nil + expect(subject.current_user).not_to eql nil end it "when organization matches but team doesn't match, redirect to /users/sign_in" do @@ -137,7 +139,7 @@ get :github end expect(response).to redirect_to new_user_session_url - expect(subject.current_user).to eql nil + expect(subject.current_user).to be nil end it "when team matches but organization doen't match, redirect to /users/sign_in" do @@ -147,7 +149,7 @@ get :github end expect(response).to redirect_to new_user_session_url - expect(subject.current_user).to eql nil + expect(subject.current_user).to be nil end end end @@ -156,10 +158,10 @@ before do APP_CONFIG["oauth"] = { "gitlab" => { "domain" => "", "group" => "" } } OmniAuth.config.add_mock(:gitlab, - provider: "gitlab", - uid: "12345", - credentials: { token: "1234567890" }, - info: { email: "test@mail.net" }) + provider: "gitlab", + uid: "12345", + credentials: { token: "1234567890" }, + info: { email: "test@mail.net" }) request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:gitlab] create :user, email: "test@mail.net" end @@ -171,7 +173,7 @@ get :gitlab end expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eql nil + expect(subject.current_user).not_to eql nil end it "when group not match, redirect to /users/sign_in" do @@ -180,14 +182,14 @@ get :gitlab end expect(response).to redirect_to new_user_session_url - expect(subject.current_user).to eql nil + expect(subject.current_user).to be nil end end it "when group isn't setted, sign in and redirect to /" do get :gitlab expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eql nil + expect(subject.current_user).not_to eql nil end end @@ -198,10 +200,10 @@ "team" => "" } } OmniAuth.config.add_mock(:gitlab, - provider: "bitbucket", - uid: "12345", - credentials: { token: "1234567890" }, - info: { email: "test@mail.net" }) + provider: "bitbucket", + uid: "12345", + credentials: { token: "1234567890" }, + info: { email: "test@mail.net" }) request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:gitlab] create :user, email: "test@mail.net" end @@ -211,7 +213,7 @@ APP_CONFIG["oauth"]["bitbucket"]["team"] = "atlant-service" get :bitbucket expect(response).to redirect_to authenticated_root_url - expect(subject.current_user).to_not eql nil + expect(subject.current_user).not_to eql nil end end end diff --git a/spec/controllers/auth/omniauth_resgistrations_controller_spec.rb b/spec/controllers/auth/omniauth_resgistrations_controller_spec.rb index c1e7a63e0..c646bb423 100644 --- a/spec/controllers/auth/omniauth_resgistrations_controller_spec.rb +++ b/spec/controllers/auth/omniauth_resgistrations_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe Auth::OmniauthRegistrationsController do diff --git a/spec/controllers/auth/registrations_controller_spec.rb b/spec/controllers/auth/registrations_controller_spec.rb index 4addf6ec3..545dd0443 100644 --- a/spec/controllers/auth/registrations_controller_spec.rb +++ b/spec/controllers/auth/registrations_controller_spec.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + require "rails_helper" describe Auth::RegistrationsController do let(:valid_session) { {} } describe "POST #create" do - before :each do + before do request.env["devise.mapping"] = Devise.mappings[:user] APP_CONFIG["signup"] = { "enabled" => true } end @@ -44,10 +46,9 @@ end describe "PUT #update" do - let!(:user) { create(:admin) } - before :each do + before do request.env["devise.mapping"] = Devise.mappings[:user] sign_in user end @@ -103,20 +104,19 @@ } expect(User.find(user.id).valid_password?("test-password")).to be true end - end describe "DELETE #destroy" do let!(:user) { create(:admin) } - before :each do + before do request.env["devise.mapping"] = Devise.mappings[:user] sign_in user end it "does not allow the removal of users" do delete :destroy, id: user.id - expect(User.find(user.id)).to_not be nil + expect(User.find(user.id)).not_to be nil end end @@ -126,7 +126,7 @@ let!(:admin) { create(:admin) } let!(:user) { create(:user) } - before :each do + before do request.env["devise.mapping"] = Devise.mappings[:user] end diff --git a/spec/controllers/auth/sessions_controller_spec.rb b/spec/controllers/auth/sessions_controller_spec.rb index 935f2a6cd..05c1188f4 100644 --- a/spec/controllers/auth/sessions_controller_spec.rb +++ b/spec/controllers/auth/sessions_controller_spec.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "rails_helper" describe Auth::SessionsController do describe "POST #create" do - before :each do + before do request.env["devise.mapping"] = Devise.mappings[:user] APP_CONFIG["signup"] = { "enabled" => true } APP_CONFIG["ldap"] = { "enabled" => true } diff --git a/spec/controllers/comments_controller_spec.rb b/spec/controllers/comments_controller_spec.rb index b55ab4e4c..8a074a810 100644 --- a/spec/controllers/comments_controller_spec.rb +++ b/spec/controllers/comments_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: comments diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb index da7ff543f..e466b4505 100644 --- a/spec/controllers/dashboard_controller_spec.rb +++ b/spec/controllers/dashboard_controller_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe DashboardController, type: :controller do let(:user) { create(:user) } - before :each do + before do create(:registry) sign_in user end diff --git a/spec/controllers/errors_controller_spec.rb b/spec/controllers/errors_controller_spec.rb index 8db9a342c..e52a538cd 100644 --- a/spec/controllers/errors_controller_spec.rb +++ b/spec/controllers/errors_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe ErrorsController do @@ -11,7 +13,7 @@ @secret_portus_password = secrets.portus_password end - before :each do + before do secrets = Rails.application.secrets secrets.secret_key_base = @secret_key_base secrets.machine_fqdn = @secret_machine_fqdn @@ -57,7 +59,7 @@ Rails.env = ActiveSupport::StringInquirer.new("test") end - before :each do + before do Rails.env = ActiveSupport::StringInquirer.new("production") end diff --git a/spec/controllers/explore_controller_spec.rb b/spec/controllers/explore_controller_spec.rb index 56e29aaf2..0d7be8c87 100644 --- a/spec/controllers/explore_controller_spec.rb +++ b/spec/controllers/explore_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe ExploreController, type: :controller do diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb index c86cf18c1..45ccf6189 100644 --- a/spec/controllers/help_controller_spec.rb +++ b/spec/controllers/help_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe HelpController, type: :controller do @@ -5,7 +7,7 @@ let!(:registry) { create(:registry, hostname: "registry.test.lan") } let!(:user) { create(:admin) } - before :each do + before do sign_in user request.env["HTTP_REFERER"] = "/" end diff --git a/spec/controllers/namespaces_controller_spec.rb b/spec/controllers/namespaces_controller_spec.rb index afc652782..2553e30c9 100644 --- a/spec/controllers/namespaces_controller_spec.rb +++ b/spec/controllers/namespaces_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: namespaces @@ -44,14 +46,14 @@ ) end - before :each do + before do # trigger creation of registry registry sign_in user end describe "GET #index" do - it "should render index template successfully [html]" do + it "renders index template successfully [html]" do get :index, valid_session expect(response).to render_template(:index) @@ -62,7 +64,7 @@ describe "GET #show" do let!(:portus) { create(:admin, username: "portus") } - it "should paginate repositories" do + it "paginates repositories" do sign_in owner get :show, id: namespace.id @@ -103,9 +105,9 @@ it "allows the user to change the visibility attribute" do sign_in owner put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :js + id: owner.namespace.id, + visibility: "visibility_public", + format: :js owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_public") @@ -115,9 +117,9 @@ it "allows the user to change the visibility attribute [json]" do sign_in owner put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :json + id: owner.namespace.id, + visibility: "visibility_public", + format: :json owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_public") @@ -127,16 +129,16 @@ # only admins may change the visibility of a user's personal namespace context "when option user_permission.change_visibility is disabled" do - before :each do + before do APP_CONFIG["user_permission"]["change_visibility"]["enabled"] = false end it "prohibits the user from changing the visibility attribute" do sign_in owner put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :js + id: owner.namespace.id, + visibility: "visibility_public", + format: :js owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_private") @@ -146,9 +148,9 @@ it "prohibits the user from changing the visibility attribute [json]" do sign_in owner put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :json + id: owner.namespace.id, + visibility: "visibility_public", + format: :json owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_private") @@ -158,9 +160,9 @@ it "allows an admin to change the visibility attribute" do sign_in admin put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :js + id: owner.namespace.id, + visibility: "visibility_public", + format: :js owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_public") @@ -170,9 +172,9 @@ it "allows an admin to change the visibility attribute [json]" do sign_in admin put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :json + id: owner.namespace.id, + visibility: "visibility_public", + format: :json owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_public") @@ -182,9 +184,9 @@ it "allows an admin to change the visibility attribute" do sign_in admin put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :js + id: owner.namespace.id, + visibility: "visibility_public", + format: :js owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_public") @@ -194,9 +196,9 @@ it "allows an admin to change the visibility attribute [json]" do sign_in admin put :change_visibility, - id: owner.namespace.id, - visibility: "visibility_public", - format: :json + id: owner.namespace.id, + visibility: "visibility_public", + format: :json owner.namespace.reload expect(owner.namespace.visibility).to eq("visibility_public") @@ -207,9 +209,9 @@ it "allows the owner of the team to change the visibility attribute" do sign_in owner put :change_visibility, - id: namespace.id, - visibility: "visibility_public", - format: :js + id: namespace.id, + visibility: "visibility_public", + format: :js namespace.reload expect(namespace.visibility).to eq("visibility_public") @@ -219,9 +221,9 @@ it "blocks users that are not part of the team" do sign_in create(:user) put :change_visibility, - id: namespace.id, - visibility: "visibility_public", - format: :js + id: namespace.id, + visibility: "visibility_public", + format: :js expect(response.status).to eq 401 end @@ -256,7 +258,7 @@ end context "non-admins are not allowed to update namespaces" do - before :each do + before do APP_CONFIG["user_permission"]["manage_namespace"]["enabled"] = false end @@ -327,7 +329,7 @@ end describe "activity tracking" do - before :each do + before do sign_in owner end @@ -415,7 +417,7 @@ end context "non-admins are not allowed to update namespaces" do - before :each do + before do APP_CONFIG["user_permission"]["manage_namespace"]["enabled"] = false end diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb index 51a0a288c..76e4adc6c 100644 --- a/spec/controllers/passwords_controller_spec.rb +++ b/spec/controllers/passwords_controller_spec.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require "rails_helper" describe PasswordsController do - before :each do + before do request.env["devise.mapping"] = Devise.mappings[:user] APP_CONFIG["email"] = { "name" => "Portus", @@ -38,7 +40,7 @@ end describe "LDAP support is enabled" do - before :each do + before do APP_CONFIG["ldap"] = { "enabled" => true } end diff --git a/spec/controllers/repositories_controller_spec.rb b/spec/controllers/repositories_controller_spec.rb index bf251c8e3..7cda3ea20 100644 --- a/spec/controllers/repositories_controller_spec.rb +++ b/spec/controllers/repositories_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: repositories @@ -33,7 +35,7 @@ end let!(:invisible_repository) { create(:repository, namespace: private_namespace) } - before :each do + before do sign_in user end @@ -79,7 +81,7 @@ let!(:tag3) { create(:tag, name: "tag3", repository: repository, digest: "2") } let!(:tag4) { create(:tag, name: "tag4", repository: repo, digest: "3") } - before :each do + before do sign_in user request.env["HTTP_REFERER"] = "/" APP_CONFIG["delete"] = { "enabled" => true } diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index ddd9babc9..1cce7ffd2 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe SearchController, type: :controller do @@ -5,7 +7,7 @@ let(:user) { create(:user) } let(:team) { create(:team, owners: [user]) } - before :each do + before do sign_in user namespace = create(:namespace, team: team, registry: registry) diff --git a/spec/controllers/tags_controller_spec.rb b/spec/controllers/tags_controller_spec.rb index 1e49c744a..154a76a2e 100644 --- a/spec/controllers/tags_controller_spec.rb +++ b/spec/controllers/tags_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: tags @@ -32,7 +34,7 @@ let!(:repository) { create(:repository, namespace: registry.global_namespace, name: "repo") } let!(:tag) { create(:tag, name: "tag0", repository: repository) } - before :each do + before do sign_in user request.env["HTTP_REFERER"] = "/" @@ -60,7 +62,7 @@ let!(:repository) { create(:repository, namespace: registry.global_namespace, name: "repo") } let!(:tag) { create(:tag, name: "tag", repository: repository) } - before :each do + before do sign_in user request.env["HTTP_REFERER"] = "/" APP_CONFIG["delete"] = { "enabled" => true } diff --git a/spec/controllers/team_users_controller_spec.rb b/spec/controllers/team_users_controller_spec.rb index 60faa6cdd..7f5378ec8 100644 --- a/spec/controllers/team_users_controller_spec.rb +++ b/spec/controllers/team_users_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: team_users @@ -23,7 +25,7 @@ let(:team) { create(:team, owners: [owner], contributors: [contributor]) } describe "as an owner of the team" do - before :each do + before do sign_in owner end @@ -133,11 +135,10 @@ expect(response.status).to eq 422 end end - end describe "as an unprivileged member of the team" do - before :each do + before do sign_in contributor end @@ -168,7 +169,7 @@ end describe "activity tracking" do - before :each do + before do sign_in owner end diff --git a/spec/controllers/teams_controller_spec.rb b/spec/controllers/teams_controller_spec.rb index 18e4ce963..12aab5e28 100644 --- a/spec/controllers/teams_controller_spec.rb +++ b/spec/controllers/teams_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: teams @@ -81,7 +83,7 @@ end describe "as a portus user" do - before :each do + before do sign_in owner end @@ -103,7 +105,7 @@ describe "PATCH #update" do it "does not allow to change the description or the team name by viewers and contributers" do - disallowed_roles = ["viewer", "contributer"] + disallowed_roles = %w[viewer contributer] disallowed_roles.each do |role| user = create(:user) TeamUser.create(team: team, user: user, role: TeamUser.roles[role]) @@ -124,7 +126,7 @@ end context "non-admins are not allowed to update teams" do - before :each do + before do APP_CONFIG["user_permission"]["manage_team"]["enabled"] = false end @@ -172,7 +174,7 @@ end it "does not allow to search by contributors or viewers" do - disallowed_roles = ["viewer", "contributer"] + disallowed_roles = %w[viewer contributer] disallowed_roles.each do |role| user = create(:user) TeamUser.create(team: team, user: user, role: TeamUser.roles[role]) @@ -209,7 +211,7 @@ end describe "activity tracking" do - before :each do + before do sign_in owner end diff --git a/spec/controllers/webhook_deliveries_controller_spec.rb b/spec/controllers/webhook_deliveries_controller_spec.rb index 9a7e248d6..66bb17eae 100644 --- a/spec/controllers/webhook_deliveries_controller_spec.rb +++ b/spec/controllers/webhook_deliveries_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_deliveries @@ -31,12 +33,12 @@ let!(:webhook) { create(:webhook, namespace: namespace) } let!(:webhook_delivery) { create(:webhook_delivery, webhook: webhook) } - before :each do + before do sign_in owner end describe "#update" do - before :each do + before do allow_any_instance_of(WebhookDelivery).to receive(:retrigger).and_return(true) end diff --git a/spec/controllers/webhook_headers_controller_spec.rb b/spec/controllers/webhook_headers_controller_spec.rb index 056f20391..3857d8968 100644 --- a/spec/controllers/webhook_headers_controller_spec.rb +++ b/spec/controllers/webhook_headers_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_headers diff --git a/spec/controllers/webhooks_controller_spec.rb b/spec/controllers/webhooks_controller_spec.rb index 70c92a5b2..f56d80e7f 100644 --- a/spec/controllers/webhooks_controller_spec.rb +++ b/spec/controllers/webhooks_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhooks @@ -50,7 +52,7 @@ let!(:webhook_header) { create(:webhook_header, webhook: webhook) } let!(:webhook_delivery) { create(:webhook_delivery, webhook: webhook) } - before :each do + before do sign_in user end @@ -69,7 +71,7 @@ end describe "GET #show" do - it "should paginate webhook deliveries" do + it "paginates webhook deliveries" do sign_in owner get :show, namespace_id: namespace.id, id: webhook.id @@ -134,7 +136,7 @@ end end - it "should delete a webhook" do + it "deletes a webhook" do sign_in owner delete :destroy, namespace_id: namespace.id, id: webhook.id expect(response.status).to eq 302 @@ -147,7 +149,7 @@ put :toggle_enabled, namespace_id: namespace.id, id: webhook.id, format: :js webhook.reload - expect(webhook).to_not be_enabled + expect(webhook).not_to be_enabled expect(response.status).to eq 200 end @@ -230,7 +232,7 @@ end context "with valid params" do - before :each do + before do sign_in owner @post_params = { webhook: valid_attributes, @@ -296,7 +298,7 @@ end context "with invalid params" do - before :each do + before do sign_in owner end @@ -411,7 +413,7 @@ end describe "activity tracking" do - before :each do + before do sign_in owner end @@ -461,20 +463,20 @@ it "tracks updates to the webhook" do expect do patch :update, - id: webhook.id, - namespace_id: namespace.id, - webhook: { url: "port.us" }, - format: "js" + id: webhook.id, + namespace_id: namespace.id, + webhook: { url: "port.us" }, + format: "js" end.to change(PublicActivity::Activity, :count).by(1) end it "tracks removal of the webhook" do expect do delete :destroy, - id: webhook.id, - namespace_id: namespace.id, - webhook: { url: "port.us" }, - format: "js" + id: webhook.id, + namespace_id: namespace.id, + webhook: { url: "port.us" }, + format: "js" end.to change(PublicActivity::Activity, :count).by(1) end end diff --git a/spec/factories/activities.rb b/spec/factories/activities.rb index 3fca988c5..3e2e04ecb 100644 --- a/spec/factories/activities.rb +++ b/spec/factories/activities.rb @@ -1,5 +1,6 @@ -FactoryGirl.define do +# frozen_string_literal: true +FactoryGirl.define do factory :activity_team_create, class: PublicActivity::Activity do owner_type "User" key "team.create" @@ -50,14 +51,14 @@ trackable_type "ApplicationToken" owner_type "User" key "application_token.created" - parameters Hash.new(application: "test application") + parameters { Hash.new(application: "test application") } end factory :activity_application_token_destroyed, class: PublicActivity::Activity do trackable_type "ApplicationToken" owner_type "User" key "application_token.destroyed" - parameters Hash.new(application: "test application") + parameters { Hash.new(application: "test application") } end factory :activity_webhook_create, class: PublicActivity::Activity do diff --git a/spec/factories/application_token.rb b/spec/factories/application_token.rb index 219865cbb..f682f27b6 100644 --- a/spec/factories/application_token.rb +++ b/spec/factories/application_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryGirl.define do factory :application_token do sequence :application do |i| diff --git a/spec/factories/comments.rb b/spec/factories/comments.rb index bb4146039..e234b17ca 100644 --- a/spec/factories/comments.rb +++ b/spec/factories/comments.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: comments diff --git a/spec/factories/namespaces.rb b/spec/factories/namespaces.rb index e412e40db..a446ff3e2 100644 --- a/spec/factories/namespaces.rb +++ b/spec/factories/namespaces.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: namespaces @@ -25,7 +27,7 @@ "namespace#{n}" end - visibility Namespace.visibilities[:visibility_private] + visibility { Namespace.visibilities[:visibility_private] } registry { association(:registry) } end end diff --git a/spec/factories/registries.rb b/spec/factories/registries.rb index b3c4259aa..d8782a17a 100644 --- a/spec/factories/registries.rb +++ b/spec/factories/registries.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: registries diff --git a/spec/factories/registry_raw_event.rb b/spec/factories/registry_raw_event.rb index 82399912f..d6505d674 100644 --- a/spec/factories/registry_raw_event.rb +++ b/spec/factories/registry_raw_event.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "../support/models/registry_raw_event" # Docker Registry v2: Push Notifications diff --git a/spec/factories/repositories.rb b/spec/factories/repositories.rb index 46c79b4fc..aa20a7331 100644 --- a/spec/factories/repositories.rb +++ b/spec/factories/repositories.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: repositories diff --git a/spec/factories/star.rb b/spec/factories/star.rb index ce4e6c214..ded5198aa 100644 --- a/spec/factories/star.rb +++ b/spec/factories/star.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryGirl.define do factory :star do repository diff --git a/spec/factories/tag.rb b/spec/factories/tag.rb index 7b2d2297e..35ab19920 100644 --- a/spec/factories/tag.rb +++ b/spec/factories/tag.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryGirl.define do factory :tag do sequence :name do |n| diff --git a/spec/factories/teams_factory.rb b/spec/factories/teams_factory.rb index fb8f1fc80..ab68993a2 100644 --- a/spec/factories/teams_factory.rb +++ b/spec/factories/teams_factory.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryGirl.define do factory :team do sequence(:name) { |n| "team_name#{n}" } diff --git a/spec/factories/users_factory.rb b/spec/factories/users_factory.rb index a8e221ac8..3f81ab7fa 100644 --- a/spec/factories/users_factory.rb +++ b/spec/factories/users_factory.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + FactoryGirl.define do factory :user do sequence(:email) { |n| "test#{n}@localhost.test.lan" } diff --git a/spec/factories/webhook_deliveries.rb b/spec/factories/webhook_deliveries.rb index 2b5a74ff9..ea1725f62 100644 --- a/spec/factories/webhook_deliveries.rb +++ b/spec/factories/webhook_deliveries.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_deliveries diff --git a/spec/factories/webhook_headers.rb b/spec/factories/webhook_headers.rb index 11f88b872..8f36a28f1 100644 --- a/spec/factories/webhook_headers.rb +++ b/spec/factories/webhook_headers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_headers diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb index ac29aee97..20e3f5032 100644 --- a/spec/factories/webhooks.rb +++ b/spec/factories/webhooks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhooks diff --git a/spec/features/admin/dashboard_spec.rb b/spec/features/admin/dashboard_spec.rb index 814c0b0aa..2b53dd385 100644 --- a/spec/features/admin/dashboard_spec.rb +++ b/spec/features/admin/dashboard_spec.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require "rails_helper" require "pp" -feature "Admin - Dashboard" do +describe "Admin - Dashboard" do let!(:registry) { create(:registry) } let!(:admin) { create(:admin) } let!(:user) { create(:user) } @@ -11,7 +13,7 @@ visit admin_dashboard_index_path end - scenario "The dashboard does not count the Portus user" do + it "The dashboard does not count the Portus user" do create_portus_user! visit admin_dashboard_index_path @@ -19,12 +21,12 @@ expect(find(".users span").text).to eq "3" end - scenario "Warn the admin that the portus user does not exist" do + it "Warn the admin that the portus user does not exist" do expect(page).to have_content("The Portus user does not exist!") create_portus_user! visit admin_dashboard_index_path - expect(page).to_not have_content("The Portus user does not exist!") + expect(page).not_to have_content("The Portus user does not exist!") end end diff --git a/spec/features/admin/registries_spec.rb b/spec/features/admin/registries_spec.rb index 2c599cb05..2876ea7ae 100644 --- a/spec/features/admin/registries_spec.rb +++ b/spec/features/admin/registries_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Admin - Registries panel" do +describe "Admin - Registries panel" do let!(:admin) { create(:admin) } before do @@ -38,7 +40,7 @@ it "shows an error if hostname is not reachable" do visit new_admin_registry_path - expect(page).to_not have_content("Skip remote checks") + expect(page).not_to have_content("Skip remote checks") fill_in "registry_name", with: "registry" fill_in "registry_hostname", with: "url_not_known:1234" @@ -71,7 +73,7 @@ expect(page).to have_current_path(admin_registries_path) expect(page).to have_content("Registry was successfully created.") - expect(Registry.any?).to be_truthy + expect(Registry).to be_any end it "shows advanced options when clicking on Show Advanced", js: true do @@ -106,7 +108,7 @@ describe "update", js: true do let!(:registry) { create(:registry) } - before :each do + before do visit edit_admin_registry_path(registry.id) end @@ -116,7 +118,7 @@ create(:repository) visit edit_admin_registry_path(registry.id) - expect(page).to_not have_css("#registry_hostname") + expect(page).not_to have_css("#registry_hostname") end it "shows an error if hostname is not reachable" do diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb index cf634b845..0b00b3d2b 100644 --- a/spec/features/admin/users_spec.rb +++ b/spec/features/admin/users_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Admin - Users panel" do +describe "Admin - Users panel" do let!(:registry) { create(:registry) } let!(:admin) { create(:admin) } let!(:user) { create(:user) } @@ -11,7 +13,7 @@ end describe "create users", js: true do - scenario "admin creates a user" do + it "admin creates a user" do visit new_admin_user_path fill_in "Username", with: "username" @@ -25,7 +27,7 @@ expect(page).to have_content("User 'username' was created successfully") end - scenario "admin adds back a removed user" do + it "admin adds back a removed user" do expect(page).to have_css("#user_#{user.id}") find("#user_#{user.id} .remove-btn").click @@ -48,7 +50,7 @@ end describe "remove users" do - scenario "allows the admin to remove other users", js: true do + it "allows the admin to remove other users", js: true do expect(page).to have_css("#user_#{user.id}") expect(page).to have_content(user.username) @@ -59,10 +61,10 @@ expect(page).to have_content("User '#{user.username}' was removed successfully") end - scenario "allows the admin to remove other users from the show page", js: true do + it "allows the admin to remove other users from the show page", js: true do visit edit_admin_user_path(user.id) - expect(page).to_not have_css("#user_#{user.id}") + expect(page).not_to have_css("#user_#{user.id}") expect(page).to have_content(user.username) find(".btn-danger").click @@ -70,12 +72,12 @@ expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound) expect(page).to have_content("User '#{user.username}' was removed successfully") - expect(page).to_not have_css("#user_#{user.id}") + expect(page).not_to have_css("#user_#{user.id}") end end describe "disable users" do - scenario "allows the admin to disable other users", js: true do + it "allows the admin to disable other users", js: true do expect(page).to have_css("#user_#{user.id}") find("#user_#{user.id} .enabled-btn").click @@ -83,7 +85,7 @@ expect(page).to have_content("User '#{user.username}' has been disabled.") end - scenario "allows the admin to enable back a user", js: true do + it "allows the admin to enable back a user", js: true do user.update_attributes(enabled: false) visit admin_users_path @@ -96,17 +98,17 @@ end describe "toggle admin" do - scenario "allows the admin to toggle a regular user into becoming an admin", js: true do + it "allows the admin to toggle a regular user into becoming an admin", js: true do expect(page).to have_css("#user_#{user.id}") expect(page).to have_css("#user_#{user.id} .admin-btn .fa-toggle-off") find("#user_#{user.id} .admin-btn").click - expect(page).to_not have_css("#user_#{user.id} .admin-btn .fa-toggle-off") + expect(page).not_to have_css("#user_#{user.id} .admin-btn .fa-toggle-off") expect(page).to have_css("#user_#{user.id} .admin-btn .fa-toggle-on") expect(page).to have_content("User '#{user.username}' is now an admin") end - scenario "allows the admin to remove another admin", js: true do + it "allows the admin to remove another admin", js: true do user.update_attributes(admin: true) visit admin_users_path @@ -114,14 +116,14 @@ expect(page).to have_css("#user_#{user.id} .admin-btn .fa-toggle-on") find("#user_#{user.id} .admin-btn").click - expect(page).to_not have_css("#user_#{user.id} .admin-btn .fa-toggle-on") + expect(page).not_to have_css("#user_#{user.id} .admin-btn .fa-toggle-on") expect(page).to have_css("#user_#{user.id} .admin-btn .fa-toggle-off") expect(page).to have_content("User '#{user.username}' is no longer an admin") end end describe "Edit user" do - scenario "allows the admin to update a user", js: true do + it "allows the admin to update a user", js: true do visit edit_admin_user_path(user) fill_in "Email", with: "another@example.com" @@ -131,7 +133,7 @@ expect(page).to have_content("User '#{user.username}' was updated successfully") end - scenario "disallows the admin to update a user with a wrong name", js: true do + it "disallows the admin to update a user with a wrong name", js: true do visit edit_admin_user_path(user) fill_in "Email", with: admin.email diff --git a/spec/features/application_spec.rb b/spec/features/application_spec.rb index efde0223d..041d493d1 100644 --- a/spec/features/application_spec.rb +++ b/spec/features/application_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Global application" do +describe "Global application" do let!(:registry) { create(:registry) } let!(:user) { create(:admin) } diff --git a/spec/features/application_tokens_spec.rb b/spec/features/application_tokens_spec.rb index bf8d51d28..699a1c6dc 100644 --- a/spec/features/application_tokens_spec.rb +++ b/spec/features/application_tokens_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Application tokens" do +describe "Application tokens" do let!(:user) { create(:user) } before do @@ -8,7 +10,7 @@ end describe "ApplicationTokens#create" do - scenario "As an user I can create a new token", js: true do + it "As an user I can create a new token", js: true do expect(user.application_tokens).to be_empty visit edit_user_registration_path @@ -28,7 +30,7 @@ expect(page).to have_content("awesome-application") end - scenario "As an user I cannot create two tokens with the same name", js: true do + it "As an user I cannot create two tokens with the same name", js: true do create(:application_token, application: "awesome-application", user: user) visit edit_user_registration_path @@ -47,7 +49,7 @@ expect(page).to have_content("Application has already been taken") end - scenario "As an user the create new token link is disabled when I reach the limit", js: true do + it "As an user the create new token link is disabled when I reach the limit", js: true do (User::APPLICATION_TOKENS_MAX - 1).times do create(:application_token, user: user) end @@ -69,7 +71,7 @@ expect(page).to have_css("#add_application_token_btn[disabled]") end - scenario "As an user I cannot create tokens once I reach my limit", js: true do + it "As an user I cannot create tokens once I reach my limit", js: true do User::APPLICATION_TOKENS_MAX.times do create(:application_token, user: user) end @@ -80,7 +82,7 @@ end describe "ApplicationTokens#destroy" do - scenario "As an user I can revoke a token", js: true do + it "As an user I can revoke a token", js: true do token = create(:application_token, user: user) visit edit_user_registration_path @@ -98,7 +100,7 @@ end describe "Toggle effect on form" do - scenario "The toggle effect works on the Create new token link", js: true do + it "The toggle effect works on the Create new token link", js: true do visit edit_user_registration_path expect(page).to have_css("#add_application_token_btn i.fa-plus-circle") diff --git a/spec/features/auth/login_feature_spec.rb b/spec/features/auth/login_feature_spec.rb index 866d5668d..e34f82e58 100644 --- a/spec/features/auth/login_feature_spec.rb +++ b/spec/features/auth/login_feature_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Login feature" do +describe "Login feature" do let!(:registry) { create(:registry) } let!(:user) { create(:user) } @@ -8,20 +10,20 @@ visit new_user_session_path end - scenario "It does not show any flash when accessing for the first time" do + it "does not show any flash when accessing for the first time" do visit root_path - expect(page).to_not have_content("You need to sign in or sign up before continuing.") + expect(page).not_to have_content("You need to sign in or sign up before continuing.") end - scenario "It does show a warning for the admin creation in LDAP support" do + it "does show a warning for the admin creation in LDAP support" do User.delete_all APP_CONFIG["first_user_admin"] = { "enabled" => false } APP_CONFIG["ldap"] = { "enabled" => true } visit new_user_session_path - expect(page).to_not have_content("The first user to be created will have admin permissions !") - expect(page).to_not have_content("Create a new account") - expect(page).to_not have_content("I forgot my password") + expect(page).not_to have_content("The first user to be created will have admin permissions !") + expect(page).not_to have_content("Create a new account") + expect(page).not_to have_content("I forgot my password") APP_CONFIG["first_user_admin"] = { "enabled" => true } visit new_user_session_path @@ -31,10 +33,10 @@ create(:admin) visit new_user_session_path - expect(page).to_not have_content("The first user to be created will have admin permissions !") + expect(page).not_to have_content("The first user to be created will have admin permissions !") end - scenario "Skips validation of minimum password length when authenticating via LDAP" do + it "Skips validation of minimum password length when authenticating via LDAP" do APP_CONFIG["ldap"] = { "enabled" => true } # Skipping validation for LDAP users is configured when the user model is first interpreted @@ -47,7 +49,7 @@ module CleanRoom ldap_user = CleanRoom::User.first ldap_user.password = "short" - expect(ldap_user.save).to eql(true) + expect(ldap_user.save).to be(true) fill_in "user_username", with: ldap_user.username fill_in "user_password", with: ldap_user.password @@ -57,8 +59,8 @@ module CleanRoom expect(page).to have_content("Repositories") end - scenario "Existing user is able using his login and password to login into Portus" do - expect(page).to_not have_content("Invalid username or password") + it "Existing user is able using his login and password to login into Portus" do + expect(page).not_to have_content("Invalid username or password") # We don't use Capybara's `login_as` method on purpose, because we are # testing the UI for logging in. @@ -68,10 +70,10 @@ module CleanRoom expect(page).to have_content("Recent activities") expect(page).to have_content("Repositories") - expect(page).to_not have_content("Signed in") + expect(page).not_to have_content("Signed in") end - scenario "Wrong password results in an error message" do + it "Wrong password results in an error message" do fill_in "user_username", with: "foo" fill_in "user_password", with: "bar" find("#login-btn").click @@ -80,13 +82,13 @@ module CleanRoom expect(page).to have_content("Invalid username or password") end - scenario "When guest tries to access dashboard - he is redirected to the login page" do + it "When guest tries to access dashboard - he is redirected to the login page" do visit root_path expect(page).to have_content("Login") expect(page).to have_current_path(root_path) end - scenario "Successful login when trying to access a page redirects back the guest" do + it "Successful login when trying to access a page redirects back the guest" do visit namespaces_path expect(page).to have_content("You need to sign in or sign up before continuing.") fill_in "user_username", with: user.username @@ -96,7 +98,7 @@ module CleanRoom expect(page).to have_content("Namespaces you have access to") end - scenario "A disabled user cannot login" do + it "A disabled user cannot login" do user.update_attributes(enabled: false) fill_in "user_username", with: user.username fill_in "user_password", with: user.password @@ -107,7 +109,7 @@ module CleanRoom expect(page).to have_current_path(new_user_session_path) end - scenario "Sign up is disabled" do + it "Sign up is disabled" do APP_CONFIG["signup"] = { "enabled" => true } visit root_path @@ -119,21 +121,21 @@ module CleanRoom visit root_path expect(page).to have_current_path(root_path) expect(page).to have_content("I forgot my password") - expect(page).to_not have_content("Create a new account") + expect(page).not_to have_content("Create a new account") end describe "User is lockable" do - before :each do + before do @attempts = Devise.maximum_attempts @unlock_in = Devise.unlock_in end - after :each do + after do Devise.maximum_attempts = @attempts Devise.unlock_in = @unlock_in end - scenario "locks the user when too many attempts have been made" do + it "locks the user when too many attempts have been made" do # Let's be fast and lock on the first attempt. Devise.maximum_attempts = 1 @@ -144,7 +146,7 @@ module CleanRoom expect(page).to have_content("Your account is locked.") user.reload - expect(user.access_locked?).to be_truthy + expect(user).to be_access_locked # The account is locked, regardless that we provide the proper password # now. @@ -154,7 +156,7 @@ module CleanRoom expect(page).to have_content("Your account is locked.") user.reload - expect(user.access_locked?).to be_truthy + expect(user).to be_access_locked # Unlock the account, the locking time has expired. Devise.unlock_in = 1.second diff --git a/spec/features/auth/logout_feature_spec.rb b/spec/features/auth/logout_feature_spec.rb index a68c5539c..cf5653624 100644 --- a/spec/features/auth/logout_feature_spec.rb +++ b/spec/features/auth/logout_feature_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Logout feature" do +describe "Logout feature" do let!(:registry) { create(:registry) } let!(:user) { create(:user) } @@ -8,13 +10,13 @@ login user end - scenario "Redirects to login screen" do + it "Redirects to login screen" do click_link("logout") expect(current_url).to eq new_user_session_url - expect(page).to_not have_content("Signed out") + expect(page).not_to have_content("Signed out") end - scenario "After login guest redirects to login page when he attempts to access dashboard again" do + it "After login guest redirects to login page when he attempts to access dashboard again" do click_link("logout") visit root_url expect(page).to have_content("Login") diff --git a/spec/features/auth/profile_feature_spec.rb b/spec/features/auth/profile_feature_spec.rb index aeddbe2e7..dfffc953a 100644 --- a/spec/features/auth/profile_feature_spec.rb +++ b/spec/features/auth/profile_feature_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Update password feature" do +describe "Update password feature" do let!(:user) { create(:admin) } before do @@ -10,7 +12,7 @@ # Changing the email - scenario "It enables the button if the user pressed a key", js: true do + it "enables the button if the user pressed a key", js: true do # Change the contents and see that it gets enabled. expect(page).to have_button("Update", disabled: true) fill_in "Email", with: "another@example.com" @@ -23,19 +25,19 @@ expect(find("#user_email").value).to eq "another@example.com" end - scenario "It disables the 'Update' button if email becomes empty", js: true do + it "disables the 'Update' button if email becomes empty", js: true do expect(page).to have_button("Update", disabled: true) fill_in "Email", with: "" expect(page).to have_button("Update", disabled: true) end - scenario "It enables the 'Update' button if email != empty", js: true do + it "enables the 'Update' button if email != empty", js: true do expect(page).to have_button("Update", disabled: true) fill_in "Email", with: "email@email.com" expect(page).to have_button("Update") end - scenario "It disables the 'Update' button if email == original value", js: true do + it "disables the 'Update' button if email == original value", js: true do expect(page).to have_button("Update", disabled: true) fill_in "Email", with: "email@email.com" expect(page).to have_button("Update") @@ -43,7 +45,7 @@ expect(page).to have_button("Update", disabled: true) end - scenario "It keeps the 'Update' button disabled if no changes", js: true do + it "keeps the 'Update' button disabled if no changes", js: true do expect(page).to have_button("Update", disabled: true) end @@ -53,15 +55,15 @@ visit edit_user_registration_path end - scenario "It shows display name field", js: true do + it "shows display name field", js: true do expect(page).to have_content("Display name") end - scenario "It keeps the 'Update' button disabled if no changes", js: true do + it "keeps the 'Update' button disabled if no changes", js: true do expect(page).to have_button("Update", disabled: true) end - scenario "It enables the 'Update' button if display name != original value", js: true do + it "enables the 'Update' button if display name != original value", js: true do expect(page).to have_button("Update", disabled: true) fill_in "Display name", with: "name" expect(page).to have_button("Update") @@ -78,7 +80,7 @@ # Changing the password - scenario "It enables/disables the submit button properly", js: true do + it "enables/disables the submit button properly", js: true do # By default it's disabled. expect(page).to have_button("Change", disabled: true) @@ -103,7 +105,7 @@ # Disabling user - scenario "It disables the current user", js: true do + it "disables the current user", js: true do create(:admin) visit edit_user_registration_path @@ -112,7 +114,7 @@ expect(page).to have_content("Login") end - scenario 'The "disable" pannel does not exists if it\'s the only admin' do - expect(page).to_not have_css("#disable-form") + it 'The "disable" pannel does not exists if it\'s the only admin' do + expect(page).not_to have_css("#disable-form") end end diff --git a/spec/features/auth/signup_feature_spec.rb b/spec/features/auth/signup_feature_spec.rb index d10cccd06..30fc07c5e 100644 --- a/spec/features/auth/signup_feature_spec.rb +++ b/spec/features/auth/signup_feature_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Signup feature" do +describe "Signup feature" do before do create(:admin) APP_CONFIG["first_user_admin"] = { "enabled" => true } @@ -11,30 +13,30 @@ let!(:registry) { create(:registry) } let(:user) { build(:user) } - scenario "As a guest I am able to signup from login page" do + it "As a guest I am able to signup from login page" do visit new_user_session_url click_link("Create a new account") expect(page).to have_field("user_email") - expect(page).to_not have_css("section.first-user") - expect(page).to_not have_css("#user_admin", visible: false) + expect(page).not_to have_css("section.first-user") + expect(page).not_to have_css("#user_admin", visible: false) end - scenario "The first user to be created is the admin if first_user_admin is enabled" do + it "The first user to be created is the admin if first_user_admin is enabled" do User.delete_all visit new_user_registration_url expect(page).to have_content("Create admin") expect(page).to have_css("#user_admin", visible: false) end - scenario "The first user to be created is NOT admin if first_user_admin is disabled" do + it "The first user to be created is NOT admin if first_user_admin is disabled" do User.delete_all APP_CONFIG["first_user_admin"] = { "enabled" => false } visit new_user_registration_url - expect(page).to_not have_content("Create admin") - expect(page).to_not have_css("#user_admin", visible: false) + expect(page).not_to have_content("Create admin") + expect(page).not_to have_css("#user_admin", visible: false) end - scenario "The portus user does not interfere with regular admin creation" do + it "The portus user does not interfere with regular admin creation" do User.delete_all create_portus_user! @@ -44,8 +46,8 @@ expect(page).to have_css("#user_admin", visible: false) end - scenario "As a guest I am able to signup" do - expect(page).to_not have_content("Create admin") + it "As a guest I am able to signup" do + expect(page).not_to have_content("Create admin") fill_in "user_username", with: user.username fill_in "user_email", with: user.email fill_in "user_password", with: user.password @@ -58,10 +60,10 @@ expect(current_url).to eq root_url end - scenario "As a guest I am able to signup with a weird username" do + it "As a guest I am able to signup with a weird username" do username = user.username + "!" - expect(page).to_not have_content("Create admin") + expect(page).not_to have_content("Create admin") fill_in "user_username", with: username fill_in "user_email", with: user.email fill_in "user_password", with: user.password @@ -76,7 +78,7 @@ expect(current_url).to eq root_url end - scenario "It always redirects to the signup page when there are no users" do + it "always redirects to the signup page when there are no users" do User.delete_all visit new_user_session_url @@ -87,7 +89,7 @@ expect(page).to have_css("section.first-user") end - scenario "It always redirects to the signin page when there are no users but LDAP is enabled" do + it "always redirects to the signin page when there are no users but LDAP is enabled" do User.delete_all APP_CONFIG["ldap"] = { "enabled" => true } @@ -98,7 +100,7 @@ expect(current_url).to eq new_user_session_url end - scenario "I am redirected to the signup page if only the portus user exists" do + it "I am redirected to the signup page if only the portus user exists" do User.delete_all create(:admin, username: "portus") @@ -110,26 +112,26 @@ expect(page).to have_css("section.first-user") end - scenario "It does not exist a link to login if there are no users" do + it "does not exist a link to login if there are no users" do expect(page).to have_content("Login") User.delete_all visit new_user_registration_url - expect(page).to_not have_content("Login") + expect(page).not_to have_content("Login") end - scenario "As a guest I can see error prohibiting my registration to be completed" do + it "As a guest I can see error prohibiting my registration to be completed" do fill_in "user_username", with: user.username fill_in "user_email", with: "gibberish" fill_in "user_password", with: user.password fill_in "user_password_confirmation", with: user.password click_button("Create account") expect(page).to have_content("Email is invalid") - expect(page).to_not have_content("Create admin") + expect(page).not_to have_content("Create admin") expect(current_url).to eq new_user_registration_url end - scenario "Multiple errors are displayed in a list" do + it "Multiple errors are displayed in a list" do fill_in "user_username", with: user.username fill_in "user_email", with: "gibberish" fill_in "user_password", with: "12341234" @@ -143,7 +145,7 @@ text: "Password confirmation doesn't match Password") end - scenario "If there are users on the system, and can move through sign_in and sign_up" do + it "If there are users on the system, and can move through sign_in and sign_up" do click_link("Login") expect(page).to have_current_path(new_user_session_path) click_link("Create a new account") @@ -155,7 +157,7 @@ APP_CONFIG["signup"] = { "enabled" => false } end - scenario "does not allow the user to access the signup page if disabled" do + it "does not allow the user to access the signup page if disabled" do visit new_user_registration_path expect(page).to have_current_path(new_user_session_path) end diff --git a/spec/features/dashboard_spec.rb b/spec/features/dashboard_spec.rb index 6584cc70c..adbe37a19 100644 --- a/spec/features/dashboard_spec.rb +++ b/spec/features/dashboard_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Dashboard page" do +describe "Dashboard page" do let!(:registry) { create(:registry) } let!(:user) { create(:admin, display_name: "docker-gangsta") } let!(:team) { create(:team, owners: [user]) } @@ -32,7 +34,7 @@ end describe "Repositories sidebar" do - scenario "Show all the repositories user has access to" do + it "Show all the repositories user has access to" do visit authenticated_root_path expect(page).to have_content("#{personal_namespace.name}/#{personal_repository.name}") expect(page).to have_content("#{namespace.name}/#{repository.name}") @@ -41,7 +43,7 @@ expect(page).to have_content("#{protected_namespace.name}/#{protected_repository.name}") end - scenario "Show personal repositories", js: true do + it "Show personal repositories", js: true do visit authenticated_root_path click_link("Personal") @@ -52,7 +54,7 @@ expect(page).not_to have_content("#{protected_namespace.name}/#{protected_repository.name}") end - scenario "Show personal repositories", js: true do + it "Show personal repositories", js: true do visit authenticated_root_path click_link("Starred") @@ -65,7 +67,7 @@ end describe "Display name" do - scenario "Shows the display name of the user when needed" do + it "Shows the display name of the user when needed" do visit authenticated_root_path expect(page).not_to have_content("docker-gangsta") APP_CONFIG["display_name"] = { "enabled" => true } diff --git a/spec/features/errors_spec.rb b/spec/features/errors_spec.rb index 5ba348a9e..cedd27cf6 100644 --- a/spec/features/errors_spec.rb +++ b/spec/features/errors_spec.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "rails_helper" -feature "custom error handler page" do +describe "custom error handler page" do describe "with custom handler setup" do - around :each do |example| + around do |example| begin Rails.application.config.consider_all_requests_local = false Rails.application.config.action_dispatch.show_exceptions = true @@ -15,12 +17,12 @@ end end - scenario "when no permissions routes to custom error page" do + it "when no permissions routes to custom error page" do visit "/teams/show?id=1234" expect(page).to have_content(/Something's wrong/) end - scenario "when no database routes to custom error page" do + it "when no database routes to custom error page" do ActiveRecord::Base.connection.disconnect! visit "/" expect(page).to have_content(/Something's wrong/) diff --git a/spec/features/explore_spec.rb b/spec/features/explore_spec.rb index 55b16d56e..b3e05bf18 100644 --- a/spec/features/explore_spec.rb +++ b/spec/features/explore_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Explore feature" do +describe "Explore feature" do let!(:registry) { create(:registry) } let!(:user) { create(:user) } diff --git a/spec/features/forgotten_password_spec.rb b/spec/features/forgotten_password_spec.rb index 95f618957..c9a4ff266 100644 --- a/spec/features/forgotten_password_spec.rb +++ b/spec/features/forgotten_password_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Forgotten password support" do +describe "Forgotten password support" do let!(:user) { create(:admin) } - before :each do + before do APP_CONFIG["signup"] = { "enabled" => true } APP_CONFIG["email"] = { "from" => "test@example.com", @@ -13,12 +15,12 @@ ActionMailer::Base.deliveries.clear end - scenario "gives the user a link to reset their password" do + it "gives the user a link to reset their password" do visit new_user_session_path expect(page).to have_content("I forgot my password") end - scenario "sends the reset email when appropiate" do + it "sends the reset email when appropiate" do visit new_user_password_path fill_in "Email", with: "random@example.com" diff --git a/spec/features/gravatar_spec.rb b/spec/features/gravatar_spec.rb index 4ea1c5585..d346f28da 100644 --- a/spec/features/gravatar_spec.rb +++ b/spec/features/gravatar_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Gravatar support" do +describe "Gravatar support" do let!(:registry) { create(:registry) } let!(:user) { create(:user) } @@ -8,13 +10,13 @@ login user end - scenario "If gravatar support is on, there should be an image" do + it "If gravatar support is on, there should be an image" do APP_CONFIG["gravatar"] = { "enabled" => true } visit root_url expect(page).to have_selector(".user-header img") end - scenario "If gravatar suppor is disabled, there should be an icon" do + it "If gravatar suppor is disabled, there should be an icon" do APP_CONFIG["gravatar"] = { "enabled" => false } visit root_url expect(page).to have_selector(".user-header .user-picture") diff --git a/spec/features/help_spec.rb b/spec/features/help_spec.rb index 25d84d35e..794fcbdbe 100644 --- a/spec/features/help_spec.rb +++ b/spec/features/help_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Help page" do +describe "Help page" do describe "API documentation support" do let!(:registry) { create(:registry) } let!(:user) { create(:admin) } @@ -9,7 +11,7 @@ login_as user, scope: :user end - scenario "A user can go to the API documentation", js: true do + it "A user can go to the API documentation", js: true do visit help_index_path click_link("API Documentation") diff --git a/spec/features/namespaces_spec.rb b/spec/features/namespaces_spec.rb index cd6ce63e2..2c9a6231f 100644 --- a/spec/features/namespaces_spec.rb +++ b/spec/features/namespaces_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Namespaces support" do +describe "Namespaces support" do let!(:registry) { create(:registry) } let!(:user) { create(:admin) } let!(:user2) { create(:user) } @@ -13,7 +15,7 @@ end describe "Namespaces#index" do - scenario "An user cannot submit with invalid form", js: true do + it "An user cannot submit with invalid form", js: true do visit namespaces_path find(".toggle-link-new-namespace").click @@ -22,7 +24,7 @@ expect(page).to have_button("Create", disabled: true) end - scenario "A user cannot leave name field empty", js: true do + it "A user cannot leave name field empty", js: true do visit namespaces_path find(".toggle-link-new-namespace").click @@ -35,7 +37,7 @@ expect(page).to have_button("Create", disabled: true) end - scenario "A user cannot fill field with an invalid name", js: true do + it "A user cannot fill field with an invalid name", js: true do visit namespaces_path find(".toggle-link-new-namespace").click @@ -47,7 +49,7 @@ expect(page).to have_button("Create", disabled: true) end - scenario "An user cannot create a namespace that already exists", js: true do + it "An user cannot create a namespace that already exists", js: true do visit namespaces_path find(".toggle-link-new-namespace").click @@ -60,7 +62,7 @@ expect(page).to have_button("Create", disabled: true) end - scenario "An user cannot create a namespace for a hidden team", js: true do + it "An user cannot create a namespace for a hidden team", js: true do visit namespaces_path find(".toggle-link-new-namespace").click @@ -74,7 +76,7 @@ expect(page).to have_button("Create", disabled: true) end - scenario "A namespace can be created from the index page", js: true do + it "A namespace can be created from the index page", js: true do namespaces_count = Namespace.count visit namespaces_path @@ -100,28 +102,28 @@ expect(page).to have_current_path(namespace_path(namespace)) end - scenario 'The "Create new namespace" link has a toggle effect', js: true do + it 'The "Create new namespace" link has a toggle effect', js: true do visit namespaces_path expect(page).to have_css(".toggle-link-new-namespace i.fa-plus-circle") - expect(page).to_not have_css(".toggle-link-new-namespace i.fa-minus-circle") + expect(page).not_to have_css(".toggle-link-new-namespace i.fa-minus-circle") find(".toggle-link-new-namespace").click wait_for_effect_on("#new-namespace-form") - expect(page).to_not have_css(".toggle-link-new-namespace i.fa-plus-circle") + expect(page).not_to have_css(".toggle-link-new-namespace i.fa-plus-circle") expect(page).to have_css(".toggle-link-new-namespace i.fa-minus-circle") find(".toggle-link-new-namespace").click wait_for_effect_on("#new-namespace-form") expect(page).to have_css(".toggle-link-new-namespace i.fa-plus-circle") - expect(page).to_not have_css(".toggle-link-new-namespace i.fa-minus-circle") + expect(page).not_to have_css(".toggle-link-new-namespace i.fa-minus-circle") end - scenario 'The "Create new namespace" keeps icon after add new namespace', js: true do + it 'The "Create new namespace" keeps icon after add new namespace', js: true do visit namespaces_path expect(page).to have_css(".toggle-link-new-namespace i.fa-plus-circle") - expect(page).to_not have_css(".toggle-link-new-namespace i.fa-minus-circle") + expect(page).not_to have_css(".toggle-link-new-namespace i.fa-minus-circle") find(".toggle-link-new-namespace").click wait_for_effect_on("#new-namespace-form") @@ -129,7 +131,7 @@ fill_in "Name", with: "valid-namespace" fill_in "Team", with: namespace.team.name - expect(page).to_not have_css(".toggle-link-new-namespace i.fa-plus-circle") + expect(page).not_to have_css(".toggle-link-new-namespace i.fa-plus-circle") expect(page).to have_css(".toggle-link-new-namespace i.fa-minus-circle") click_button "Create" @@ -137,10 +139,10 @@ wait_for_effect_on("#new-namespace-form") expect(page).to have_css(".toggle-link-new-namespace i.fa-plus-circle") - expect(page).to_not have_css(".toggle-link-new-namespace i.fa-minus-circle") + expect(page).not_to have_css(".toggle-link-new-namespace i.fa-minus-circle") end - scenario "The namespace visibility can be changed", js: true do + it "The namespace visibility can be changed", js: true do visit namespaces_path id = namespace.id @@ -162,7 +164,7 @@ expect(namespace.visibility_public?).to be true end - scenario "Namespace table sorting is reachable through url", js: true do + it "Namespace table sorting is reachable through url", js: true do # sort asc visit namespaces_path(ns_sort_asc: true) @@ -184,7 +186,7 @@ expect(page).to have_css("th:nth-child(4) .fa-sort-amount-desc") end - scenario "URL is updated when namespaces column is sorted", js: true do + it "URL is updated when namespaces column is sorted", js: true do visit namespaces_path expect(page).to have_css(".namespaces-panel:last-of-type th:nth-child(4)") @@ -204,7 +206,7 @@ expect(page).to have_current_path(path) end - scenario "Namespace table pagination is reachable through url", js: true do + it "Namespace table pagination is reachable through url", js: true do create_list(:namespace, 15, team: team, registry: registry) # page 2 @@ -218,7 +220,7 @@ expect(page).to have_css(".namespaces-panel .pagination li.active:nth-child(2)") end - scenario "URL is updated when page is changed", js: true do + it "URL is updated when page is changed", js: true do create_list(:namespace, 15, team: team, registry: registry) visit namespaces_path @@ -240,7 +242,7 @@ end describe "#update" do - scenario "user inputs a team does not exist", js: true do + it "user inputs a team does not exist", js: true do visit namespace_path(namespace.id) find(".toggle-link-edit-namespace").click @@ -250,7 +252,7 @@ expect(page).to have_content("Selected team does not exist") end - scenario "user removes the team", js: true do + it "user removes the team", js: true do visit namespace_path(namespace.id) find(".toggle-link-edit-namespace").click @@ -259,7 +261,7 @@ expect(page).to have_content("Team can't be blank") end - scenario "user updates namespace's team", js: true do + it "user updates namespace's team", js: true do new_team = create(:team, owners: [user]) visit namespace_path(namespace.id) @@ -277,7 +279,7 @@ expect(page).to have_content("Namespace '#{namespace.name}' was updated successfully") end - scenario "user updates namespace's description", js: true do + it "user updates namespace's description", js: true do visit namespace_path(namespace.id) find(".toggle-link-edit-namespace").click @@ -309,7 +311,7 @@ expect(page).to have_content("Pull Viewer") end - scenario "An user sees dropdown for 'Show webhooks'", js: true do + it "An user sees dropdown for 'Show webhooks'", js: true do visit namespace_path(namespace.id) expect(page).not_to have_content("Show webhooks") diff --git a/spec/features/repositories_comments_spec.rb b/spec/features/repositories_comments_spec.rb index 4fcaf5f7f..c946f4e1b 100644 --- a/spec/features/repositories_comments_spec.rb +++ b/spec/features/repositories_comments_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Repositories comments support" do +describe "Repositories comments support" do let!(:registry) { create(:registry, hostname: "registry.test.lan") } let!(:admin) { create(:admin) } let!(:owner) { create(:user) } @@ -34,7 +36,7 @@ end describe "comment#create" do - scenario "An user comments on a repository under a public namespace", js: true do + it "An user comments on a repository under a public namespace", js: true do visit repository_path(visible_repository) expect(page).to have_content("Nobody has left a comment") @@ -50,7 +52,7 @@ expect(page).not_to have_content("Nobody has left a comment") end - scenario "An user comments on a repository under a protected namespace", js: true do + it "An user comments on a repository under a protected namespace", js: true do visit repository_path(protected_repository) expect(page).to have_content("Nobody has left a comment") @@ -66,7 +68,7 @@ expect(page).not_to have_content("Nobody has left a comment") end - scenario "An admin comments on any repository", js: true do + it "An admin comments on any repository", js: true do login_as admin, scope: :user visit repository_path(invisible_repository) @@ -83,13 +85,13 @@ expect(page).not_to have_content("Nobody has left a comment") end - scenario "An user cannot comment on a repository without access", js: true do + it "An user cannot comment on a repository without access", js: true do visit repository_path(invisible_repository) expect(page).to have_content("You are not authorized to access this page") end - scenario "An user cannot comment an empty text", js: true do + it "An user cannot comment an empty text", js: true do visit repository_path(visible_repository) find(".add-comment").click @@ -104,7 +106,7 @@ end describe "comment#delete" do - scenario "An user deletes his own comment", js: true do + it "An user deletes his own comment", js: true do login_as owner, scope: :user visit repository_path(commented_repository) @@ -117,7 +119,7 @@ expect(page).not_to have_content(comment.body) end - scenario "An user cannot delete other users' comment", js: true do + it "An user cannot delete other users' comment", js: true do visit repository_path(commented_repository) expect(page).to have_content(comment.body) @@ -125,7 +127,7 @@ expect(page).not_to have_content("Delete comment") end - scenario "An admin deletes any comment", js: true do + it "An admin deletes any comment", js: true do login_as admin, scope: :user visit repository_path(commented_repository) diff --git a/spec/features/repositories_spec.rb b/spec/features/repositories_spec.rb index 105a00afc..2d827161c 100644 --- a/spec/features/repositories_spec.rb +++ b/spec/features/repositories_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" def find_tag_checkbox(name) @@ -5,7 +7,7 @@ def find_tag_checkbox(name) tag.find(:xpath, "../..").find("input[type='checkbox']") end -feature "Repositories support" do +describe "Repositories support" do let!(:registry) { create(:registry, hostname: "registry.test.lan") } let!(:user) { create(:admin) } let!(:user2) { create(:user) } @@ -25,7 +27,7 @@ def find_tag_checkbox(name) create_list(:repository, 15, namespace: namespace) end - scenario "Repositories table sorting is reachable through url" do + it "Repositories table sorting is reachable through url" do # sort asc visit repositories_path(sort_asc: true) @@ -47,7 +49,7 @@ def find_tag_checkbox(name) expect(page).to have_css("th:nth-child(2) .fa-sort-amount-desc") end - scenario "URL is updated when repositories column is sorted" do + it "URL is updated when repositories column is sorted" do visit repositories_path expect(page).to have_css(".repositories-panel:last-of-type th:nth-child(2)") @@ -67,7 +69,7 @@ def find_tag_checkbox(name) expect(page).to have_current_path(path) end - scenario "Repositories table pagination is reachable through url" do + it "Repositories table pagination is reachable through url" do # page 2 visit repositories_path(page: 2) @@ -79,7 +81,7 @@ def find_tag_checkbox(name) expect(page).to have_css(".repositories-panel .pagination li.active:nth-child(2)") end - scenario "URL is updated when page is changed" do + it "URL is updated when page is changed" do visit repositories_path expect(page).to have_css(".repositories-panel:last-of-type .pagination li:nth-child(3)") @@ -101,14 +103,14 @@ def find_tag_checkbox(name) end describe "repository#show" do - scenario "Visual aid for each role is shown properly" do + it "Visual aid for each role is shown properly" do visit repository_path(repository) info = page.find(".repository-information-icon")["data-content"] expect(info).to have_content("You can push images") expect(info).to have_content("You can pull images") expect(info).to have_content("You are an owner of this repository") - expect(info).to_not have_content("You are a contributor in this repository") - expect(info).to_not have_content("You are a viewer in this repository") + expect(info).not_to have_content("You are a contributor in this repository") + expect(info).not_to have_content("You are a viewer in this repository") login_as user2, scope: :user visit repository_path(repository) @@ -116,20 +118,20 @@ def find_tag_checkbox(name) expect(info).to have_content("You can push images") expect(info).to have_content("You can pull images") expect(info).to have_content("You are a contributor in this repository") - expect(info).to_not have_content("You are an owner of this repository") - expect(info).to_not have_content("You are a viewer in this repository") + expect(info).not_to have_content("You are an owner of this repository") + expect(info).not_to have_content("You are a viewer in this repository") login_as user3, scope: :user visit repository_path(repository) info = page.find(".repository-information-icon")["data-content"] expect(info).to have_content("You can pull images") expect(info).to have_content("You are a viewer in this repository") - expect(info).to_not have_content("You can push images") - expect(info).to_not have_content("You are an owner of this repository") - expect(info).to_not have_content("You are a contributor in this repository") + expect(info).not_to have_content("You can push images") + expect(info).not_to have_content("You are an owner of this repository") + expect(info).not_to have_content("You are a contributor in this repository") end - scenario "A user can star a repository", js: true do + it "A user can star a repository", js: true do visit repository_path(repository) expect(page).to have_css("#toggle_star") find("#toggle_star").click @@ -142,7 +144,7 @@ def find_tag_checkbox(name) expect(repo.stars.count).to be 1 end - scenario "A user can unstar a repository", js: true do + it "A user can unstar a repository", js: true do visit repository_path(starred_repo) expect(page).to have_css("#toggle_star") find("#toggle_star").click @@ -155,27 +157,27 @@ def find_tag_checkbox(name) expect(repo.stars.count).to be 0 end - scenario "Groupped tags are handled properly" do + it "Groupped tags are handled properly" do ["", "", "same", "same", "another", "yet-another"].each_with_index do |digest, idx| create(:tag, name: "tag#{idx}", author: user, repository: repository, digest: digest, image_id: "Image", created_at: idx.hours.ago) end - expectations = [["tag0"], ["tag1"], ["tag2", "tag3"], ["tag4"], ["tag5"]] + expectations = [["tag0"], ["tag1"], %w[tag2 tag3], ["tag4"], ["tag5"]] visit repository_path(repository) page.all(".tags tr").each_with_index do |row, idx| - expect(row.text.include?("Image")).to be_truthy + expect(row.text).to include("Image") # Skip the header. next if idx == 0 - expectations[idx - 1].each { |tag| expect(row.text.include?(tag)).to be_truthy } + expectations[idx - 1].each { |tag| expect(row.text).to include(tag) } end end - scenario "it works if both the digest and the image_id are blank" do + it "works if both the digest and the image_id are blank" do create(:tag, author: user, repository: repository, digest: nil, image_id: nil) create(:tag, author: user, repository: repository, digest: "nonblank", image_id: nil) @@ -189,16 +191,16 @@ def find_tag_checkbox(name) enable_security_vulns_module! end - scenario "The delete feature is available only for allowed users" do + it "The delete feature is available only for allowed users" do visit repository_path(repository) expect(page).to have_content("Delete repository") login_as user2, scope: :user visit repository_path(repository) - expect(page).to_not have_content("Delete repository") + expect(page).not_to have_content("Delete repository") end - scenario "A user can delete a repository", js: true do + it "A user can delete a repository", js: true do visit repository_path(repository) repository_count = Repository.count @@ -208,8 +210,8 @@ def find_tag_checkbox(name) expect(page).to have_content("Repository removed with all its tags") end - scenario "A user deletes a tag", js: true do - ["lorem", "ipsum"].each_with_index do |digest, idx| + it "A user deletes a tag", js: true do + %w[lorem ipsum].each_with_index do |digest, idx| create(:tag, name: "tag#{idx}", author: user, repository: repository, digest: digest, image_id: "Image", created_at: idx.hours.ago, updated_at: idx.hours.ago) end @@ -217,7 +219,7 @@ def find_tag_checkbox(name) VCR.use_cassette("registry/get_image_manifest_tags", record: :none) do visit repository_path(repository) - expect(page).to_not have_content("Delete tag") + expect(page).not_to have_content("Delete tag") find_tag_checkbox("tag0").click expect(page).to have_content("Delete tag") @@ -226,8 +228,8 @@ def find_tag_checkbox(name) end end - scenario "A user deletes tags", js: true do - ["lorem", "ipsum", "ipsum"].each_with_index do |digest, idx| + it "A user deletes tags", js: true do + %w[lorem ipsum ipsum].each_with_index do |digest, idx| create(:tag, name: "tag#{idx}", author: user, repository: repository, digest: digest, image_id: "Image", created_at: idx.hours.ago, updated_at: idx.hours.ago) end @@ -235,7 +237,7 @@ def find_tag_checkbox(name) VCR.use_cassette("registry/get_image_manifest_tags", record: :none) do visit repository_path(repository) - expect(page).to_not have_content("Delete tags") + expect(page).not_to have_content("Delete tags") find_tag_checkbox("tag1").click expect(page).to have_content("Delete tags") find(".tag-delete-btn").click @@ -243,8 +245,8 @@ def find_tag_checkbox(name) end end - scenario "A user deletes a repository by deleting all tags", js: true do - ["lorem", "ipsum"].each_with_index do |digest, idx| + it "A user deletes a repository by deleting all tags", js: true do + %w[lorem ipsum].each_with_index do |digest, idx| create(:tag, name: "tag#{idx}", author: user, repository: repository, digest: digest, image_id: "Image", created_at: idx.hours.ago) end @@ -252,7 +254,7 @@ def find_tag_checkbox(name) VCR.use_cassette("registry/get_image_manifest_tags", record: :none) do visit repository_path(repository) - expect(page).to_not have_content("Delete tags") + expect(page).not_to have_content("Delete tags") find("tbody tr input[type='checkbox']", match: :first) all("tbody tr input[type='checkbox']").each(&:click) expect(page).to have_content("Delete tags") diff --git a/spec/features/teams_spec.rb b/spec/features/teams_spec.rb index 918c9fcab..8a50f125e 100644 --- a/spec/features/teams_spec.rb +++ b/spec/features/teams_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Teams support" do +describe "Teams support" do let!(:registry) { create(:registry) } let!(:user) { create(:admin) } let!(:team) { create(:team, owners: [user]) } @@ -10,7 +12,7 @@ end describe "teams#index", js: true do - scenario "A user cannot create an empty team" do + it "A user cannot create an empty team" do visit teams_path find(".toggle-link-new-team").click @@ -23,7 +25,7 @@ expect(page).to have_button("Add", disabled: true) end - scenario "A team cannot be created if the name has already been picked" do + it "A team cannot be created if the name has already been picked" do visit teams_path find(".toggle-link-new-team").click @@ -36,7 +38,7 @@ expect(page).to have_button("Add", disabled: true) end - scenario "A team can be created from the index page" do + it "A team can be created from the index page" do teams_count = Team.count visit teams_path @@ -55,25 +57,25 @@ expect(Team.count).to eql(teams_count + 1) end - scenario 'The "Create new team" link has a toggle effect' do + it 'The "Create new team" link has a toggle effect' do visit teams_path expect(page).to have_css(".toggle-link-new-team i.fa-plus-circle") - expect(page).to_not have_css(".toggle-link-new-team i.fa-minus-circle") + expect(page).not_to have_css(".toggle-link-new-team i.fa-minus-circle") find(".toggle-link-new-team").click wait_for_effect_on("#new-team-form") - expect(page).to_not have_css(".toggle-link-new-team i.fa-plus-circle") + expect(page).not_to have_css(".toggle-link-new-team i.fa-plus-circle") expect(page).to have_css(".toggle-link-new-team i.fa-minus-circle") find(".toggle-link-new-team").click wait_for_effect_on("#new-team-form") expect(page).to have_css(".toggle-link-new-team i.fa-plus-circle") - expect(page).to_not have_css(".toggle-link-new-team i.fa-minus-circle") + expect(page).not_to have_css(".toggle-link-new-team i.fa-minus-circle") end - scenario "The name of each team is a link" do + it "The name of each team is a link" do visit teams_path expect(page).to have_link(team.name) @@ -81,7 +83,7 @@ expect(page).to have_current_path(team_path(team)) end - scenario "Disabled users do not count" do + it "Disabled users do not count" do user = create(:user) team.viewers = [user] team.save! @@ -94,12 +96,12 @@ visit teams_path expect(page).to have_css("td:nth-child(4)", text: "1") - expect(page).to_not have_css("td:nth-child(4)", text: "2") + expect(page).not_to have_css("td:nth-child(4)", text: "2") end end describe "teams#update" do - scenario "Team name can be updated", js: true do + it "Team name can be updated", js: true do visit team_path(team) click_button "Edit team" @@ -121,11 +123,11 @@ let!(:another) { create(:user) } let!(:another_admin) { create(:admin) } - before :each do + before do visit team_path(team) end - scenario "A namespace can be created from the team page", js: true do + it "A namespace can be created from the team page", js: true do namespaces_count = Namespace.count # The form appears after clicking the "Add namespace" link. @@ -154,7 +156,7 @@ expect(page).to have_current_path(namespace_path(namespace)) end - scenario "Namespace table sorting is reachable through url", js: true do + it "Namespace table sorting is reachable through url", js: true do # sort asc visit team_path(team, ns_sort_asc: true) @@ -176,7 +178,7 @@ expect(page).to have_css(".namespaces-panel th:nth-child(4) .fa-sort-amount-desc") end - scenario "URL is updated when namespaces column is sorted", js: true do + it "URL is updated when namespaces column is sorted", js: true do # sort asc & created_at find(".namespaces-panel th:nth-child(4)").click @@ -192,7 +194,7 @@ expect(page).to have_current_path(path) end - scenario "Namespace table pagination is reachable through url", js: true do + it "Namespace table pagination is reachable through url", js: true do create_list(:namespace, 15, team: team, registry: registry) # page 2 @@ -206,7 +208,7 @@ expect(page).to have_css(".namespaces-panel .pagination li.active:nth-child(2)") end - scenario "URL is updated when page is changed", js: true do + it "URL is updated when page is changed", js: true do create_list(:namespace, 15, team: team, registry: registry) visit team_path(team) @@ -226,7 +228,7 @@ expect(page).to have_current_path(team_path(team, ns_page: 1)) end - scenario "An user can be added as a team member", js: true do + it "An user can be added as a team member", js: true do find("#add_team_user_btn").click find("#team_user_role").select "Contributor" find("#team_user_user").set another.username @@ -240,7 +242,7 @@ expect(page).to have_css(".team-users-wrapper tbody tr:last-child .role", text: "Contributor") end - scenario "An admin can only be added as a team owner", js: true do + it "An admin can only be added as a team owner", js: true do find("#add_team_user_btn").click find("#team_user_role").select "Contributor" find("#team_user_user").set another_admin.username @@ -257,7 +259,7 @@ expect(page).to have_css(".team-users-wrapper tbody tr:last-child .role", text: "Owner") end - scenario "New team members have to exist on the system", js: true do + it "New team members have to exist on the system", js: true do find("#add_team_user_btn").click find("#team_user_role").select "Contributor" find("#team_user_user").set "grumpy" @@ -270,7 +272,7 @@ expect(page).to have_content("User cannot be found") end - scenario "A team member can be kicked out from a team", js: true do + it "A team member can be kicked out from a team", js: true do tu = TeamUser.create!(team: team, user: another, role: TeamUser.roles["viewer"]) visit team_path(team) @@ -284,7 +286,7 @@ expect(page).to have_content("User '#{another.username}' was removed from the team") end - scenario "The only member of a team cannot be removed", js: true do + it "The only member of a team cannot be removed", js: true do find("#team_users .delete-team-user-btn").click find(".popover-content .btn-primary").click diff --git a/spec/features/webhooks_spec.rb b/spec/features/webhooks_spec.rb index a3e444722..7da67e34c 100644 --- a/spec/features/webhooks_spec.rb +++ b/spec/features/webhooks_spec.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" -feature "Webhooks support" do +describe "Webhooks support" do let!(:registry) { create(:registry) } let!(:user) { create(:admin) } let!(:user2) { create(:user) } @@ -20,7 +22,7 @@ end describe "#index" do - scenario "A user cannot create an empty webhook", js: true do + it "A user cannot create an empty webhook", js: true do webhooks_count = namespace.webhooks.count visit namespace_webhooks_path(namespace) @@ -33,7 +35,7 @@ expect(page).to have_current_path(namespace_webhooks_path(namespace)) end - scenario "A user can create a webhook from namespace's webhooks page", js: true do + it "A user can create a webhook from namespace's webhooks page", js: true do webhooks_count = namespace.webhooks.count visit namespace_webhooks_path(namespace) @@ -58,24 +60,24 @@ expect(page).to have_current_path(namespace_webhook_path(namespace, webhook)) end - scenario 'The "Create new webhook" link has a toggle effect', js: true do + it 'The "Create new webhook" link has a toggle effect', js: true do visit namespace_webhooks_path(namespace) expect(page).to have_css("#add_webhook_btn i.fa-plus-circle") - expect(page).to_not have_css("#add_webhook_btn i.fa-minus-circle") + expect(page).not_to have_css("#add_webhook_btn i.fa-minus-circle") find("#add_webhook_btn").click - expect(page).to_not have_css("#add_webhook_btn i.fa-plus-circle") + expect(page).not_to have_css("#add_webhook_btn i.fa-plus-circle") expect(page).to have_css("#add_webhook_btn i.fa-minus-circle") find("#add_webhook_btn").click expect(page).to have_css("#add_webhook_btn i.fa-plus-circle") - expect(page).to_not have_css("#add_webhook_btn i.fa-minus-circle") + expect(page).not_to have_css("#add_webhook_btn i.fa-minus-circle") end - scenario "A user enables/disables webhook", js: true do + it "A user enables/disables webhook", js: true do visit namespace_webhooks_path(namespace) id = webhook.id @@ -93,7 +95,7 @@ expect(page).to have_content("Webhook '#{webhook.url}' is now enabled") end - scenario "A user deletes a webhook", js: true do + it "A user deletes a webhook", js: true do visit namespace_webhooks_path(namespace) id = webhook.id @@ -109,7 +111,7 @@ end describe "#show" do - scenario "A user updates webhooks info", js: true do + it "A user updates webhooks info", js: true do visit namespace_webhook_path(namespace, webhook) find(".edit-webhook-link").click @@ -125,11 +127,11 @@ expect(page).to have_content("Webhook 'new-webhook-url' has been updated successfully") end - scenario 'The "Edit webhook" link has a toggle effect', js: true do + it 'The "Edit webhook" link has a toggle effect', js: true do visit namespace_webhook_path(namespace, webhook) expect(page).to have_css(".edit-webhook-link .fa-pencil") - expect(page).to_not have_css(".edit-webhook-link .fa-close") + expect(page).not_to have_css(".edit-webhook-link .fa-close") find(".edit-webhook-link").click @@ -139,11 +141,11 @@ find(".edit-webhook-link").click expect(page).to have_css(".edit-webhook-link .fa-pencil") - expect(page).to_not have_css(".edit-webhook-link .fa-close") + expect(page).not_to have_css(".edit-webhook-link .fa-close") end describe "webhook_header" do - scenario "A user can create a header from webhook's page", js: true do + it "A user can create a header from webhook's page", js: true do webhook_headers_count = webhook.headers.count visit namespace_webhook_path(namespace, webhook) @@ -165,7 +167,7 @@ expect(webhook.headers.count).to eql webhook_headers_count + 1 end - scenario "A user cannot create a header that already exists", js: true do + it "A user cannot create a header that already exists", js: true do webhook_headers_count = webhook.headers.count visit namespace_webhook_path(namespace, webhook) @@ -185,7 +187,7 @@ expect(webhook.headers.count).to eql webhook_headers_count end - scenario "A user deletes a webhook header", js: true do + it "A user deletes a webhook header", js: true do visit namespace_webhook_path(namespace, webhook) id = webhook_header.id @@ -204,21 +206,21 @@ expect(page).not_to have_content(webhook_header.value) end - scenario 'The "Create new header" link has a toggle effect', js: true do + it 'The "Create new header" link has a toggle effect', js: true do visit namespace_webhook_path(namespace, webhook) expect(page).to have_css("#add_webhook_header_btn i.fa-plus-circle") - expect(page).to_not have_css("#add_webhook_header_btn i.fa-minus-circle") + expect(page).not_to have_css("#add_webhook_header_btn i.fa-minus-circle") find("#add_webhook_header_btn").click - expect(page).to_not have_css("#add_webhook_header_btn i.fa-plus-circle") + expect(page).not_to have_css("#add_webhook_header_btn i.fa-plus-circle") expect(page).to have_css("#add_webhook_header_btn i.fa-minus-circle") find("#add_webhook_header_btn").click expect(page).to have_css("#add_webhook_header_btn i.fa-plus-circle") - expect(page).to_not have_css("#add_webhook_header_btn i.fa-minus-circle") + expect(page).not_to have_css("#add_webhook_header_btn i.fa-minus-circle") end end end diff --git a/spec/helpers/activities_helper_spec.rb b/spec/helpers/activities_helper_spec.rb index 6c1714bae..326db8b7e 100644 --- a/spec/helpers/activities_helper_spec.rb +++ b/spec/helpers/activities_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe ActivitiesHelper, type: :helper do diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 8f166b483..0a299e9f4 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe ApplicationHelper, type: :helper do @@ -63,7 +65,7 @@ def time_tag(first, second, _args) it "filters html" do html_tag = "" - expect(markdown(html_tag)).to eq "

alert('foo');

\n" + expect(markdown(html_tag)).to eq "

alert('foo');

\n" end end @@ -108,19 +110,19 @@ def time_tag(first, second, _args) describe "#js_route" do # controller.class === ActionView::TestCase::TestController - it "should return controller_name/action_name format" do + it "returns controller_name/action_name format" do allow(controller).to receive(:action_name) { "action" } expect(js_route).to eq("action_view/test_case/test/action") end - it "should alias update as edit action name" do + it "aliases update as edit action name" do allow(controller).to receive(:action_name) { "update" } expect(js_route).to eq("action_view/test_case/test/edit") end - it "should alias create as new action name" do + it "aliases create as new action name" do allow(controller).to receive(:action_name) { "create" } expect(js_route).to eq("action_view/test_case/test/new") diff --git a/spec/helpers/comments_helper_spec.rb b/spec/helpers/comments_helper_spec.rb index 73dc944c1..da476c8c2 100644 --- a/spec/helpers/comments_helper_spec.rb +++ b/spec/helpers/comments_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe CommentsHelper, type: :helper do diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb index 12f44675a..522893324 100644 --- a/spec/helpers/namespaces_helper_spec.rb +++ b/spec/helpers/namespaces_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe NamespacesHelper, type: :helper do diff --git a/spec/helpers/registries_helper_spec.rb b/spec/helpers/registries_helper_spec.rb index 6804269f5..b41675da9 100644 --- a/spec/helpers/registries_helper_spec.rb +++ b/spec/helpers/registries_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe RegistriesHelper, type: :helper do diff --git a/spec/helpers/repositories_helper_spec.rb b/spec/helpers/repositories_helper_spec.rb index 10570ccba..41e86a021 100644 --- a/spec/helpers/repositories_helper_spec.rb +++ b/spec/helpers/repositories_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" class CatalogJobMock < CatalogJob @@ -17,9 +19,9 @@ def update_registry!(catalog) let(:contributor) { create(:user) } let(:team) do create(:team, - owners: [owner], - contributors: [contributor], - viewers: [viewer]) + owners: [owner], + contributors: [contributor], + viewers: [viewer]) end let(:namespace) { create(:namespace, team: team) } let(:repo) { create(:repository, namespace: namespace) } @@ -154,11 +156,11 @@ def update_registry!(catalog) it "returns true if any security vulnerability server is configured" do enable_security_vulns_module! - expect(helper.security_vulns_enabled?).to be_truthy + expect(helper).to be_security_vulns_enabled end it "returns false if no security vulnerability server is configured" do - expect(helper.security_vulns_enabled?).to be_falsy + expect(helper).not_to be_security_vulns_enabled end end @@ -169,11 +171,11 @@ def update_registry!(catalog) two: [] } - expect(helper.vulnerable?(vulnerabilities)).to be_truthy + expect(helper).to be_vulnerable(vulnerabilities) end it "returns false if no vulnerabilities were found" do - expect(helper.vulnerable?(nil)).to be_falsey + expect(helper).not_to be_vulnerable(nil) end it "returns false if no security vulnerability server is configured" do @@ -182,7 +184,7 @@ def update_registry!(catalog) two: [] } - expect(helper.vulnerable?(vulnerabilities)).to be_falsy + expect(helper).not_to be_vulnerable(vulnerabilities) end end end diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 11eebbc0f..a6009a67f 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -1,7 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe SearchHelper, type: :helper do - describe "build_search_category_url" do it "returns true if current user is an owner of the team" do expected = "#{search_index_path}?utf8=✓&search=&type=repositories" diff --git a/spec/helpers/sessions_helper_spec.rb b/spec/helpers/sessions_helper_spec.rb index b36fe6c86..71caed03a 100644 --- a/spec/helpers/sessions_helper_spec.rb +++ b/spec/helpers/sessions_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe SessionsHelper, type: :helper do diff --git a/spec/helpers/teams_helper_spec.rb b/spec/helpers/teams_helper_spec.rb index e31b38b0b..065cca124 100644 --- a/spec/helpers/teams_helper_spec.rb +++ b/spec/helpers/teams_helper_spec.rb @@ -1,7 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" RSpec.describe TeamsHelper, type: :helper do - let(:admin) { create(:admin) } let(:owner) { create(:user) } let(:viewer) { create(:user) } @@ -71,7 +72,7 @@ end describe "team_user_role_icon" do - before(:each) do + before do team end @@ -95,7 +96,7 @@ end describe "role_icon_class" do - before(:each) do + before do team end diff --git a/spec/integration/client_spec.rb b/spec/integration/client_spec.rb index c58932a4e..6caa7ecce 100644 --- a/spec/integration/client_spec.rb +++ b/spec/integration/client_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "integration/helper" require "portus/registry_client" @@ -34,7 +36,7 @@ def push_test_images integration "Client" do it "tells that a registry is reachable" do client = Portus::RegistryClient.new(registry_hostname) - expect(client.reachable?).to be_truthy + expect(client).to be_reachable end it "fetches the catalog of pushed repositories" do @@ -60,8 +62,8 @@ def push_test_images client = Portus::RegistryClient.new(registry_hostname) manifest = client.manifest("registre", "2.3.1") - expect(manifest[0]).to_not be_empty - expect(manifest[1]).to_not be_empty + expect(manifest[0]).not_to be_empty + expect(manifest[1]).not_to be_empty expect(manifest[2]["schemaVersion"]).to eq 2 end diff --git a/spec/integration/helper.rb b/spec/integration/helper.rb index 94a26b039..0bcfa688b 100644 --- a/spec/integration/helper.rb +++ b/spec/integration/helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "docker" require "pty" require "spec_helper" @@ -30,6 +32,7 @@ def integration(name, tags = {}, &blk) end # Setup the describe block for the given parameters. +# rubocop:disable Metrics/MethodLength def setup_describe(name, version, rebuild, tags, &blk) describe "#{name} (distribution: #{version}) (LDAP: #{ldap?})", tags do before :all do @@ -51,7 +54,7 @@ def setup_describe(name, version, rebuild, tags, &blk) WebMock.disable_net_connect! end - before :each do + before do WebMock.allow_net_connect! VCR.turn_off! @@ -59,7 +62,7 @@ def setup_describe(name, version, rebuild, tags, &blk) `docker restart integration_portus` end - after :each do + after do VCR.turn_on! WebMock.disable_net_connect! end @@ -67,6 +70,7 @@ def setup_describe(name, version, rebuild, tags, &blk) instance_eval(&blk) end end +# rubocop:enable Metrics/MethodLength # Fetch some needed parameters from the given tags. It returns a two-sized # array where the first item is an array of the docker distribution versions, @@ -77,10 +81,10 @@ def parameters_from_tags(tags) versions = SUPPORTED_DISTRIBUTION_VERSIONS if tags.key?(:distribution) filter = if tags[:distribution].is_a? Array - tags[:distribution] - else - [tags[:distribution]] - end + tags[:distribution] + else + [tags[:distribution]] + end versions &= filter end @@ -224,6 +228,7 @@ def setup_db! # - rebuild: whether the image has to be rebuilt or not. # - env: a list of additional environment variables to be passed. # - ip: the IP that the Portus container should have. +# rubocop:disable Metrics/MethodLength def setup_portus!(rebuild = true, env = [], address = nil) dir = File.expand_path(File.dirname(__FILE__) + "../../../") @@ -264,6 +269,7 @@ def setup_portus!(rebuild = true, env = [], address = nil) start_container!("integration_portus:latest", "integration_portus", opts) end end +# rubocop:enable Metrics/MethodLength def setup_templates! # Render the template @@ -426,7 +432,7 @@ def eventually_expect(expect) # Cleanup all the containers that might be running. def cleanup! - ["integration_db", "integration_portus", "integration_ldap"].each do |container| + %w[integration_db integration_portus integration_ldap].each do |container| cleanup_container!(container) end cleanup_distribution! diff --git a/spec/integration/login_spec.rb b/spec/integration/login_spec.rb index 4e526224a..5ad975c63 100644 --- a/spec/integration/login_spec.rb +++ b/spec/integration/login_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "integration/helper" integration "Login" do @@ -5,7 +7,7 @@ let(:email) { "john@example.com" } let(:password) { "12341234" } - after :each do + after do `docker logout #{registry_hostname}` end @@ -23,7 +25,6 @@ create_user("mc!", email, password, true) expect { login(name, password, email) }.not_to raise_error - end it "allows users to push images with multiple tags" do diff --git a/spec/jobs/catalog_job_spec.rb b/spec/jobs/catalog_job_spec.rb index 4e11d05c3..150f17220 100644 --- a/spec/jobs/catalog_job_spec.rb +++ b/spec/jobs/catalog_job_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" # Just opens up protected methods so they can be used in the test suite. @@ -23,7 +25,7 @@ def update_registry!(catalog) # Global repos. ns = Namespace.where(global: true) repos = Repository.where(namespace: ns) - expect(repos.map(&:name).sort).to match_array(["alpine", "busybox"]) + expect(repos.map(&:name).sort).to match_array(%w[alpine busybox]) tags = Repository.find_by(name: "busybox").tags expect(tags.map(&:name)).to match_array(["0.1", "latest"]) tags = Repository.find_by(name: "alpine", namespace: ns).tags @@ -38,7 +40,7 @@ def update_registry!(catalog) it "does nothing if there is no registry" do job = CatalogJobMock.new - expect { job.perform }.to_not raise_error + expect { job.perform }.not_to raise_error end it "raises an exception when there has been a problem in /v2/_catalog" do @@ -90,7 +92,6 @@ def update_registry!(catalog) tags = repo.tags expect(tags.map(&:name)).to match_array(["latest"]) end - end describe "Database already filled with repos" do @@ -107,9 +108,9 @@ def update_registry!(catalog) job = CatalogJobMock.new job.update_registry!([ { "name" => "busybox", "tags" => ["latest", "0.1"] }, - { "name" => "#{namespace.name}/repo1", "tags" => ["latest"] }, - { "name" => "#{namespace.name}/repo2", "tags" => ["latest", "tag2"] }, - { "name" => "#{namespace.name}/alpine", "tags" => ["latest"] } + { "name" => "#{namespace.name}/repo1", "tags" => ["latest"] }, + { "name" => "#{namespace.name}/repo2", "tags" => %w[latest tag2] }, + { "name" => "#{namespace.name}/alpine", "tags" => ["latest"] } ]) # Global repos @@ -121,13 +122,13 @@ def update_registry!(catalog) # User namespaces. repos = Repository.where(namespace: namespace) - expect(repos.map(&:name).sort).to match_array(["alpine", "repo1", "repo2"]) + expect(repos.map(&:name).sort).to match_array(%w[alpine repo1 repo2]) tags = Repository.find_by(name: "alpine").tags expect(tags.map(&:name)).to match_array(["latest"]) tags = Repository.find_by(name: "repo1").tags expect(tags.map(&:name)).to match_array(["latest"]) tags = Repository.find_by(name: "repo2").tags - expect(tags.map(&:name)).to match_array(["latest", "tag2"]) + expect(tags.map(&:name)).to match_array(%w[latest tag2]) end end diff --git a/spec/lib/omni_auth/strategies/bitbucket_spec.rb b/spec/lib/omni_auth/strategies/bitbucket_spec.rb index a5bdd10f6..0c8efeeb1 100644 --- a/spec/lib/omni_auth/strategies/bitbucket_spec.rb +++ b/spec/lib/omni_auth/strategies/bitbucket_spec.rb @@ -1,24 +1,26 @@ +# frozen_string_literal: true + require "rails_helper" describe OmniAuth::Strategies::Bitbucket do + subject { described_class.new({}) } + let(:access_token) { instance_double("AccessToken", options: {}) } let(:parsed_response) { instance_double("ParsedResponse") } let(:response) { instance_double("Response", parsed: parsed_response) } - subject { OmniAuth::Strategies::Bitbucket.new({}) } - context "get user data" do let(:parsed_mails) { instance_double("ParsedResponse") } let(:response_mails) { instance_double("Response", parsed: parsed_mails) } let(:info) { { name: "User", nickname: "user", email: "test@mail.net" } } - before :each do + before do expect(access_token).to receive(:get).with("/api/2.0/user").and_return(response) expect(subject).to receive(:access_token).and_return(access_token).at_least(:once) end context "#info" do - it "should return user info" do + it "returns user info" do expect(parsed_response).to receive(:[]).and_return("User", "user").twice expect(parsed_mails).to receive(:[]).and_return( [{ "email" => "test@mail.net", "is_primary" => true, "is_confirmed" => true }] @@ -30,7 +32,7 @@ end context "#extra" do - it "should return extra user info" do + it "returns extra user info" do expect(subject.extra[:raw_info]).to eql parsed_response end end @@ -45,7 +47,7 @@ end context "#build_access_token_with_team_check" do - before :each do + before do expect(subject).to receive(:build_access_token_without_team_check).and_return(access_token) end @@ -56,7 +58,7 @@ context "with team setting" do # let(:parsed_response) { instance_double("ParsedResponse") } # let(:response_mails) { instance_double("Response", parsed: parsed_mails) } - before :each do + before do expect(parsed_response).to receive(:[]).with("values") .and_return([{ "username" => "test-team" }]) expect(access_token).to receive(:get).with("/api/2.0/teams?role=member") diff --git a/spec/lib/portus/background/security_scanning_spec.rb b/spec/lib/portus/background/security_scanning_spec.rb index 45234d365..d67bec579 100644 --- a/spec/lib/portus/background/security_scanning_spec.rb +++ b/spec/lib/portus/background/security_scanning_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" require "portus/background/security_scanning" @@ -7,7 +9,7 @@ let!(:registry) { create(:registry, hostname: "my.registry:5000", use_ssl: true) } let!(:repository) { create(:repository, name: "repo", namespace: registry.global_namespace) } - before :each do + before do APP_CONFIG["security"] = { "clair" => { "server" => "http://localhost:6060" }, "zypper" => { "server" => "" }, @@ -18,18 +20,18 @@ describe "#work?" do it "returns false if security scanning is not enabled" do APP_CONFIG["security"]["clair"]["server"] = "" - expect(subject.work?).to be_falsey + expect(subject).not_to be_work end it "returns true if there are tags to be scanned" do create(:tag, name: "tag", repository: repository, digest: "1", author: admin) - expect(subject.work?).to be_truthy + expect(subject).to be_work end it "returns false if no tags are to be scanned" do create(:tag, name: "tag", repository: repository, digest: "1", author: admin, scanned: Tag.statuses[:scan_done]) - expect(subject.work?).to be_falsey + expect(subject).not_to be_work end end @@ -45,7 +47,7 @@ tag.reload expect(tag.scanned).to eq Tag.statuses[:scan_done] - expect(tag.vulnerabilities).to_not be_empty + expect(tag.vulnerabilities).not_to be_empty end it "ignores it when a push has happened while fetching vulnerabilities" do @@ -100,8 +102,8 @@ subject.execute! expect(count).to eq 1 - expect(Tag.all.all? { |t| t.scanned == Tag.statuses[:scan_done] }).to be_truthy - expect(Tag.all.all? { |t| t.vulnerabilities == ["something"] }).to be_truthy + expect(Tag.all).to(be_all { |t| t.scanned == Tag.statuses[:scan_done] }) + expect(Tag.all).to(be_all { |t| t.vulnerabilities == ["something"] }) end end diff --git a/spec/lib/portus/db_spec.rb b/spec/lib/portus/db_spec.rb index 2363ccfc6..0c322c113 100644 --- a/spec/lib/portus/db_spec.rb +++ b/spec/lib/portus/db_spec.rb @@ -1,49 +1,51 @@ +# frozen_string_literal: true + require "rails_helper" describe Portus::DB do describe "ping" do it "returns :ready on the usual case" do - expect(Portus::DB.ping).to eq :ready + expect(described_class.ping).to eq :ready end it "returns :empty if the DB is still initializing" do allow(::Portus::DB).to receive(:migrations?).and_return(false) - expect(Portus::DB.ping).to eq :empty + expect(described_class.ping).to eq :empty end it "returns :missing if the DB is missing" do allow(::Portus::DB).to receive(:migrations?).and_raise(ActiveRecord::NoDatabaseError, "a") - expect(Portus::DB.ping).to eq :missing + expect(described_class.ping).to eq :missing end it "returns :down if the DB is down" do allow(::Portus::DB).to receive(:migrations?).and_raise(Mysql2::Error, "a") - expect(Portus::DB.ping).to eq :down + expect(described_class.ping).to eq :down end end describe "mysql?" do - before :each do + before do ENV["PORTUS_DB_ADAPTER"] = nil end - after :each do + after do ENV["PORTUS_DB_ADAPTER"] = CONFIGURED_DB_ADAPTER end it "returns true if the adapter is mysql" do ENV["PORTUS_DB_ADAPTER"] = "mysql2" - expect(Portus::DB.mysql?).to be_truthy + expect(described_class).to be_mysql end it "returns true if no adapter has been configured" do - expect(Portus::DB.mysql?).to be_truthy + expect(described_class).to be_mysql end it "returns false if postgresql has been configured instead" do ENV["PORTUS_DB_ADAPTER"] = "postgresql" - expect(Portus::DB.mysql?).to be_falsey + expect(described_class).not_to be_mysql end end end diff --git a/spec/lib/portus/deprecation_error_spec.rb b/spec/lib/portus/deprecation_error_spec.rb index b1bb8af1e..c9c9fe490 100644 --- a/spec/lib/portus/deprecation_error_spec.rb +++ b/spec/lib/portus/deprecation_error_spec.rb @@ -1,11 +1,15 @@ +# frozen_string_literal: true + require "rails_helper" describe Portus::DeprecationError do - let(:message) { "example" } subject(:error) { described_class.new(message) } + let(:message) { "example" } + context "#to_s" do subject { error.to_s } + it "prefixes the message with [DEPRECATED]" do is_expected.to eq "[DEPRECATED] #{message}" end diff --git a/spec/lib/portus/jwt_token_spec.rb b/spec/lib/portus/jwt_token_spec.rb index e582d30c8..9281ed187 100644 --- a/spec/lib/portus/jwt_token_spec.rb +++ b/spec/lib/portus/jwt_token_spec.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + require "rails_helper" # Let's open up some instance variables for testing purposes. Portus::JwtToken.class_eval { attr_reader :account, :service } describe Portus::JwtToken do - let(:mock) { Portus::JwtToken.new("", "", nil) } + let(:mock) { described_class.new("", "", nil) } let(:registry) { create(:registry) } let(:scope) { Namespace::AuthScope.new(registry, "repository:samalba/my-app:push") } @@ -15,7 +17,7 @@ describe ".jwt_kid" do # TODO: @eotchi add more keys to test against it "returns known by libtrust kid of a given key" do - kid = Portus::JwtToken.kid(mock.private_key) + kid = described_class.kid(mock.private_key) expect(kid).to eq "PTWT:FNJE:7TW7:ULI7:DZQA:JJJI:RDJQ:2M76:HD6G:ZRSC:VPIF:O5BU" end end diff --git a/spec/lib/portus/ldap_spec.rb b/spec/lib/portus/ldap_spec.rb index f42ab7bcb..c0ed7434f 100644 --- a/spec/lib/portus/ldap_spec.rb +++ b/spec/lib/portus/ldap_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" class LdapMockAdapter @@ -106,24 +108,24 @@ def load_configuration_test } end - before :each do - allow_any_instance_of(Portus::LDAP).to receive(:authenticate!).and_call_original + before do + allow_any_instance_of(described_class).to receive(:authenticate!).and_call_original end it "sets self.enabled? accordingly" do - expect(Portus::LDAP.enabled?).to be_falsey + expect(described_class).not_to be_enabled APP_CONFIG["ldap"] = {} - expect(Portus::LDAP.enabled?).to be_falsey + expect(described_class).not_to be_enabled APP_CONFIG["ldap"] = { "enabled" => "lala" } - expect(Portus::LDAP.enabled?).to be_falsey + expect(described_class).not_to be_enabled APP_CONFIG["ldap"] = { "enabled" => false } - expect(Portus::LDAP.enabled?).to be_falsey + expect(described_class).not_to be_enabled APP_CONFIG["ldap"] = { "enabled" => true } - expect(Portus::LDAP.enabled?).to be true + expect(described_class.enabled?).to be true end # Let's make code coverage happy @@ -156,7 +158,7 @@ def load_configuration_test lm = LdapMock.new(username: "name", password: "1234") cfg = lm.load_configuration_test - expect(cfg).to_not be nil + expect(cfg).not_to be nil expect(cfg.opts[:host]).to eq "hostname" expect(cfg.opts[:port]).to eq 389 expect(cfg.opts[:encryption]).to be nil @@ -226,7 +228,7 @@ def load_configuration_test ] end - before :each do + before do APP_CONFIG["ldap"] = { "enabled" => true } end @@ -243,7 +245,7 @@ def load_configuration_test _, created = lm.find_or_create_user_test! expect(User.count).to eq 1 - expect(User.find_by(username: "name")).to_not be nil + expect(User.find_by(username: "name")).not_to be nil expect(created).to be_truthy end diff --git a/spec/lib/portus/migrate_spec.rb b/spec/lib/portus/migrate_spec.rb index 3293b8715..f912843ff 100644 --- a/spec/lib/portus/migrate_spec.rb +++ b/spec/lib/portus/migrate_spec.rb @@ -1,49 +1,51 @@ +# frozen_string_literal: true + require "rails_helper" describe Portus::Migrate do describe "from_humanized_time" do it "evaluates as minutes if it's an integer" do - val = Portus::Migrate.from_humanized_time(3, 2) + val = described_class.from_humanized_time(3, 2) expect(val).to eq 3.minutes end it "returns as minutes if it's a string of an integer" do - val = Portus::Migrate.from_humanized_time("3", 2) + val = described_class.from_humanized_time("3", 2) expect(val).to eq 3.minutes end it "returns the default on error" do - val = Portus::Migrate.from_humanized_time(/asd/, 2) + val = described_class.from_humanized_time(/asd/, 2) expect(val).to eq 2.minutes - val = Portus::Migrate.from_humanized_time("badformat", 2) + val = described_class.from_humanized_time("badformat", 2) expect(val).to eq 2.minutes end it "raises a deprecation error when an expression is given" do - expect { Portus::Migrate.from_humanized_time("3.minutes", 2) }.to \ + expect { described_class.from_humanized_time("3.minutes", 2) }.to \ raise_error(Portus::DeprecationError) - expect { Portus::Migrate.from_humanized_time("3.seconds", 2) }.to \ + expect { described_class.from_humanized_time("3.seconds", 2) }.to \ raise_error(Portus::DeprecationError) end end describe "registry_config" do - before :each do + before do @registry = APP_CONFIG["registry"] end - after :each do + after do APP_CONFIG["registry"] = @registry APP_CONFIG["jwt_expiration_time"] = nil end it "returns a value depending of the format" do - expect(Portus::Migrate.registry_config("jwt_expiration_time")).to_not be_nil + expect(described_class.registry_config("jwt_expiration_time")).not_to be_nil APP_CONFIG["registry"] = nil APP_CONFIG["jwt_expiration_time"] = { "value" => 5 } - expect { Portus::Migrate.registry_config("jwt_expiration_time") }.to \ + expect { described_class.registry_config("jwt_expiration_time") }.to \ raise_error(Portus::DeprecationError) end end diff --git a/spec/lib/portus/registry_client_spec.rb b/spec/lib/portus/registry_client_spec.rb index b2a80cef9..1735764f2 100644 --- a/spec/lib/portus/registry_client_spec.rb +++ b/spec/lib/portus/registry_client_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" # The RegistryClient defaults to the "portus" user if no credentials were @@ -10,18 +12,6 @@ def initialize(host) end end -# This class mocks a response object by providing the `code` method. This -# method will return whatever has been passed in the initializer. -class RegistryMockedStatusResponse - def initialize(status) - @status = status - end - - def code - @status - end -end - # This class mocks the `perform_request` by returning whatever has been request # in the initializer. class RegistryPerformRequest < Portus::RegistryClient @@ -33,7 +23,7 @@ def perform_request(_endpoint, _verb, _authentication) # We don't care about the given parameters. return nil if @status.nil? - RegistryMockedStatusResponse.new(@status) + OpenStruct.new(code: @status) end end @@ -56,7 +46,7 @@ def fetch_link_test(header) VCR.turned_off do WebMock.disable_net_connect! s = stub_request(:get, "https://#{registry_server}/v2/") - registry = Portus::RegistryClient.new(registry_server, true) + registry = described_class.new(registry_server, true) registry.perform_request("") expect(s).to have_been_requested end @@ -80,7 +70,7 @@ def fetch_link_test(header) let(:path) { "" } it "can obtain an authentication token" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -94,7 +84,7 @@ def fetch_link_test(header) end it "raise an exception when the user credentials are wrong" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -109,7 +99,7 @@ def fetch_link_test(header) end it "raises an AuthorizationError when the credentials are always wrong" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -137,7 +127,7 @@ def fetch_link_test(header) end it "raises a NoBearerRealmException when the bearer realm is not found" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -160,7 +150,7 @@ def fetch_link_test(header) end it "raises a NoBearerRealmException when the bearer realm is not found" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -198,7 +188,7 @@ def fetch_link_test(header) it "authenticates and fetches the image manifest" do VCR.use_cassette("registry/get_image_manifest", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -213,7 +203,7 @@ def fetch_link_test(header) it "fails if the image is not found" do VCR.use_cassette("registry/get_missing_image_manifest", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -227,7 +217,7 @@ def fetch_link_test(header) end it "raises an exception when the return code is different from 200 or 401" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -243,7 +233,7 @@ def fetch_link_test(header) expect do registry.manifest(repository, tag) - end.to raise_error(RuntimeError) + end.to raise_error(::Portus::RegistryClient::ManifestError) end ensure WebMock.allow_net_connect! @@ -257,7 +247,7 @@ def fetch_link_test(header) create(:admin, username: "portus") VCR.use_cassette("registry/get_registry_catalog", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -284,7 +274,7 @@ def fetch_link_test(header) .to_return(body: "{\"name\": \"busybox#{i}\", \"tags\":[\"latest\"]} ", status: 200) end - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -301,7 +291,7 @@ def fetch_link_test(header) create(:admin, username: "portus") VCR.use_cassette("registry/get_registry_one_fails", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -317,7 +307,7 @@ def fetch_link_test(header) it "fails if this version of registry does not implement /v2/_catalog" do VCR.use_cassette("registry/get_missing_catalog_endpoint", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -331,7 +321,7 @@ def fetch_link_test(header) end it "raises an exception when the return code is different from 200 or 401" do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, username, @@ -367,7 +357,7 @@ def fetch_link_test(header) create(:admin, username: "portus") VCR.use_cassette("registry/catalog_lots_of_tags", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -383,7 +373,7 @@ def fetch_link_test(header) context "deleting a blob from an image" do it "deleting a blob that does not exist" do VCR.use_cassette("registry/delete_missing_blob", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -399,7 +389,7 @@ def fetch_link_test(header) it "deleting blobs is not enabled on the server" do VCR.use_cassette("registry/delete_disabled", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -415,7 +405,7 @@ def fetch_link_test(header) it "allows the deletion of blobs" do VCR.use_cassette("registry/delete_blob", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", @@ -430,7 +420,7 @@ def fetch_link_test(header) it "does what we expect on a Bad Request" do VCR.use_cassette("registry/invalid_delete_blob", record: :none) do - registry = Portus::RegistryClient.new( + registry = described_class.new( registry_server, false, "portus", diff --git a/spec/lib/portus/registry_notification_spec.rb b/spec/lib/portus/registry_notification_spec.rb index 12679cbb9..9e7429c65 100644 --- a/spec/lib/portus/registry_notification_spec.rb +++ b/spec/lib/portus/registry_notification_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe Portus::RegistryNotification do @@ -54,8 +56,10 @@ end # This is a real even notification as given by docker distribution v2.3 - # rubocop:disable Metrics/LineLength let(:version23) do + sha = "sha256:b9c8a3839b2754e0fc4309e0f994f617d43814996805388e2f9d977db3fa7967" + ua = "docker/1.9.1 go/go1.5.2 git-commit/a34a1d5 kernel/4.4.0-1-default os/linux arch/amd64" + { "id" => "7dc1c55c-dfe2-4699-ab0b-8f32e89882ce", "timestamp" => "2016-02-05T11:16:14.917994087+01:00", @@ -66,14 +70,14 @@ "digest" => "sha256:b9c8a3839b2754e0fc4309e0f994f617d43814996805388e2f9d977db3fa7967", "length" => 2739, "repository" => "mssola/lala", - "url" => "https://registry.mssola.cat:5000/v2/mssola/lala/manifests/sha256:b9c8a3839b2754e0fc4309e0f994f617d43814996805388e2f9d977db3fa7967" + "url" => "https://registry.mssola.cat:5000/v2/mssola/lala/manifests/#{sha}" }, "request" => { "id" => "e30471d8-39c3-41c0-abc2-775ed43e81c9", "addr" => "127.0.0.1:54032", "host" => "registry.mssola.cat:5000", "method" => "PUT", - "useragent" => "docker/1.9.1 go/go1.5.2 git-commit/a34a1d5 kernel/4.4.0-1-default os/linux arch/amd64" + "useragent" => ua }, "actor" => { "name" => "mssola" @@ -84,7 +88,6 @@ } } end - # rubocop:enable Metrics/LineLength it "processes all the relevant events" do body["events"] << relevant @@ -93,21 +96,21 @@ expect(Repository).to receive(:handle_push_event).with(relevant) expect(Repository).to receive(:handle_delete_event).with(delete) expect(Repository).to receive(:handle_push_event).with(version23) - Portus::RegistryNotification.process!(body, Repository) + described_class.process!(body, Repository) end it "does not process the same event multiple times" do body["events"] = [version23] expect(Repository).to receive(:handle_push_event).with(version23) - Portus::RegistryNotification.process!(body, Repository) + described_class.process!(body, Repository) expect(RegistryEvent.count).to eq 1 event = RegistryEvent.find_by(event_id: version23["id"]) expect(event.event_id).to eq version23["id"] expect(event.repository).to eq version23["target"]["repository"] - expect(Repository).to_not receive(:handle_push_event).with(version23) - Portus::RegistryNotification.process!(body, Repository) + expect(Repository).not_to receive(:handle_push_event).with(version23) + described_class.process!(body, Repository) expect(RegistryEvent.count).to eq 1 end diff --git a/spec/lib/portus/request_error_spec.rb b/spec/lib/portus/request_error_spec.rb new file mode 100644 index 000000000..0d68d65b8 --- /dev/null +++ b/spec/lib/portus/request_error_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +describe ::Portus::RequestError do + it "sumarizes the given request error" do + e = StandardError.new + + expect do + raise ::Portus::RequestError.new(exception: e, message: "something") + end.to raise_error(::Portus::RequestError, "StandardError: something") + end +end diff --git a/spec/lib/portus/security/clair_spec.rb b/spec/lib/portus/security/clair_spec.rb index 1bb71f9e1..e39cca10a 100644 --- a/spec/lib/portus/security/clair_spec.rb +++ b/spec/lib/portus/security/clair_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" require "portus/security" @@ -11,7 +13,7 @@ def expect_cve_match(cves, given, expected) end describe ::Portus::SecurityBackend::Clair do - before :each do + before do APP_CONFIG["security"] = { "clair" => { "server" => "http://my.clair:6060" diff --git a/spec/lib/portus/security_spec.rb b/spec/lib/portus/security_spec.rb index 07640279a..f3a4fcdf6 100644 --- a/spec/lib/portus/security_spec.rb +++ b/spec/lib/portus/security_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe ::Portus::Security do @@ -13,9 +15,9 @@ } } - sec = ::Portus::Security.new("some", "tag") - expect(sec.available?).to be_falsey - expect(::Portus::Security.enabled?).to be_falsey + sec = described_class.new("some", "tag") + expect(sec).not_to be_available + expect(described_class).not_to be_enabled end it "is enabled when at least one has been configured" do @@ -29,9 +31,9 @@ } } - sec = ::Portus::Security.new("some", "tag") - expect(sec.available?).to be_truthy - expect(::Portus::Security.enabled?).to be_truthy + sec = described_class.new("some", "tag") + expect(sec).to be_available + expect(described_class).to be_enabled end it "is enabled when all has been configured" do @@ -45,9 +47,9 @@ } } - sec = ::Portus::Security.new("some", "tag") - expect(sec.available?).to be_truthy - expect(::Portus::Security.enabled?).to be_truthy + sec = described_class.new("some", "tag") + expect(sec).to be_available + expect(described_class).to be_enabled end end end diff --git a/spec/lib/tasks/migrate_rake_spec.rb b/spec/lib/tasks/migrate_rake_spec.rb deleted file mode 100644 index dad6beaeb..000000000 --- a/spec/lib/tasks/migrate_rake_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require "rails_helper" -require "rake" - -def capture_stdout(&_block) - original_stdout = $stdout - $stdout = fake = StringIO.new - begin - yield - ensure - $stdout = original_stdout - end - fake.string -end - -describe "Updating namespaces from 2.0 to 2.1" do - let!(:registry) { create(:registry) } - let!(:admin) { create(:admin, username: "miquelsabate", ldap_name: "miquel.sabate") } - - before :each do - load Rails.root.join("lib", "tasks", "migrate.rake") - Rake::Task.define_task(:environment) - APP_CONFIG["ldap"] = { "enabled" => true } - ENV["PORTUS_FORCE_LDAP_NAME_UPDATE"] = "true" - end - - after :each do - ENV["PORTUS_FORCE_LDAP_NAME_UPDATE"] = nil - end - - it "handles updating namespaces" do - ns = Namespace.find_by(name: "miquelsabate") - - capture_stdout do - Rake.application.invoke_task("migrate:update_personal_namespaces") - Rake.application.invoke_task("migrate:update_ldap_names") - end - - user = User.find_by(username: "miquel.sabate") - expect(user.namespace.id).to eq ns.id - expect(user.username).to eq user.ldap_name - end -end diff --git a/spec/models/application_token_spec.rb b/spec/models/application_token_spec.rb index dafb7afa6..7a3cb5059 100644 --- a/spec/models/application_token_spec.rb +++ b/spec/models/application_token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: application_tokens @@ -22,7 +24,7 @@ it "checks for the uniqueness of application" do create(:application_token, application: "test", user: user) expect do - ApplicationToken.create!( + described_class.create!( application: "test", token_hash: "hash", token_salt: "salt", @@ -36,7 +38,7 @@ user2 = create(:user) expect do - ApplicationToken.create!( + described_class.create!( application: "test", token_hash: "hash", token_salt: "salt", @@ -51,7 +53,7 @@ end expect do - ApplicationToken.create!( + described_class.create!( application: "test", token_hash: "hash", token_salt: "salt", diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index 58d89b414..b0eece192 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: comments @@ -18,8 +20,8 @@ require "rails_helper" describe Comment do - it { should belong_to(:repository) } - it { should belong_to(:author) } + it { is_expected.to belong_to(:repository) } + it { is_expected.to belong_to(:author) } it "has a valid factory" do expect { Factory.build(:comment).to be_valid } diff --git a/spec/models/namespace/auth_scope_spec.rb b/spec/models/namespace/auth_scope_spec.rb index 0ed262e92..a478dab95 100644 --- a/spec/models/namespace/auth_scope_spec.rb +++ b/spec/models/namespace/auth_scope_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe Namespace::AuthScope, type: :model do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index adecaddb4..31727726f 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: namespaces @@ -22,11 +24,11 @@ require "rails_helper" describe Namespace do - it { should have_many(:repositories) } - it { should belong_to(:team) } - it { should validate_presence_of(:name) } - it { should allow_value("test1", "1test", "another-test").for(:name) } - it { should_not allow_value("TesT1", "1Test", "another_test!").for(:name) } + it { is_expected.to have_many(:repositories) } + it { is_expected.to belong_to(:team) } + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to allow_value("test1", "1test", "another-test").for(:name) } + it { is_expected.not_to allow_value("TesT1", "1Test", "another_test!").for(:name) } context "validator" do let(:registry) { create(:registry) } @@ -35,32 +37,32 @@ let(:namespace) { create(:namespace, team: team) } it "checks for the uniqueness of the namespace inside of the registry" do - Namespace.create!(team: team, registry: registry, name: "lala") + described_class.create!(team: team, registry: registry, name: "lala") expect do - Namespace.create!(team: team, name: "lala", registry: registry) + described_class.create!(team: team, name: "lala", registry: registry) end.to raise_error(ActiveRecord::RecordInvalid, /Name has already been taken/) end it "checks tat the namespace name follows the proper format" do ["-a", "&a", "_invalid", "R2D2", "also_invalid_"].each do |name| - n = Namespace.new(team: team, registry: registry, name: name) - expect(n).to_not be_valid + n = described_class.new(team: team, registry: registry, name: name) + expect(n).not_to be_valid end ["a", "1", "1.0", "r2d2", "thingie", "is_valid"].each do |name| - n = Namespace.new(team: team, registry: registry, name: name) + n = described_class.new(team: team, registry: registry, name: name) expect(n).to be_valid end end it "checks the length of the name" do name = (0...100).map { ("a".."z").to_a[rand(26)] }.join - n = Namespace.new(team: team, registry: registry, name: name) + n = described_class.new(team: team, registry: registry, name: name) expect(n).to be_valid name = (0...270).map { ("a".."z").to_a[rand(26)] }.join - n = Namespace.new(team: team, registry: registry, name: name) - expect(n).to_not be_valid + n = described_class.new(team: team, registry: registry, name: name) + expect(n).not_to be_valid end end @@ -70,15 +72,15 @@ let!(:portus) { create(:admin, username: "portus") } it "returns true when the given namespace belongs to portus" do - expect(Namespace.find_by(name: portus.username).portus?).to be_truthy - expect(Namespace.find_by(name: owner.username).portus?).to be_falsey + expect(described_class.find_by(name: portus.username)).to be_portus + expect(described_class.find_by(name: owner.username)).not_to be_portus end it "only returns the namespaces that are not portus" do # The registry creates one extra user, so we have two personal # namespace. Furthermore, there's the global one. - expect(Namespace.not_portus.count).to eq 3 - expect(Namespace.count).to eq 4 + expect(described_class.not_portus.count).to eq 3 + expect(described_class.count).to eq 4 end end @@ -87,12 +89,12 @@ namespace = create( :namespace, global: true, - visibility: Namespace.visibilities[:visibility_public] + visibility: described_class.visibilities[:visibility_public] ) - namespace.visibility = Namespace.visibilities[:visibility_private] + namespace.visibility = described_class.visibilities[:visibility_private] expect(namespace.save).to be false - namespace.visibility = Namespace.visibilities[:visibility_protected] + namespace.visibility = described_class.visibilities[:visibility_protected] expect(namespace.save).to be true end end @@ -114,7 +116,7 @@ global_namespace = create( :namespace, global: true, - visibility: Namespace.visibilities[:visibility_public], + visibility: described_class.visibilities[:visibility_public], registry: registry ) expect(global_namespace.clean_name).to eq(registry.hostname) @@ -130,28 +132,28 @@ let!(:repo) { create(:repository, namespace: namespace) } it "works for global namespaces" do - ns = Namespace.find_by(global: true) - namespace, name = Namespace.get_from_name(repo.name) + ns = described_class.find_by(global: true) + namespace, name = described_class.get_from_name(repo.name) expect(namespace.id).to eq ns.id expect(name).to eq repo.name end it "works for user namespaces" do - ns, name = Namespace.get_from_name("#{namespace.name}/#{repo.name}") + ns, name = described_class.get_from_name("#{namespace.name}/#{repo.name}") expect(ns.id).to eq namespace.id expect(name).to eq repo.name end context "when providing a registry" do it "works for global namespaces" do - ns = Namespace.find_by(global: true) - namespace, name = Namespace.get_from_name(repo.name, registry) + ns = described_class.find_by(global: true) + namespace, name = described_class.get_from_name(repo.name, registry) expect(namespace.id).to eq ns.id expect(name).to eq repo.name end it "works for user namespaces" do - ns, name = Namespace.get_from_name("#{namespace.name}/#{repo.name}", registry) + ns, name = described_class.get_from_name("#{namespace.name}/#{repo.name}", registry) expect(ns.id).to eq namespace.id expect(name).to eq repo.name end @@ -164,35 +166,35 @@ it "does nothing on already valid names" do ["name", "a", "a_a", "45", "n4", "h2o", "flavio.castelli"].each do |name| - expect(Namespace.make_valid(name)).to eq name + expect(described_class.make_valid(name)).to eq name end end it "returns nil if the name cannot be changed" do ["", ".", "_", "-", "!!!!"].each do |name| - expect(Namespace.make_valid(name)).to be_nil + expect(described_class.make_valid(name)).to be_nil end end it "changes invalid names that can be saved" do - expect(Namespace.make_valid("_name")).to eq "name" - expect(Namespace.make_valid("name_")).to eq "name" - expect(Namespace.make_valid("___name_-aa__")).to eq "name_aa" - expect(Namespace.make_valid("_ma._.n")).to eq "ma_n" - expect(Namespace.make_valid("ma_s")).to eq "ma_s" - expect(Namespace.make_valid("!lol!")).to eq "lol" - expect(Namespace.make_valid("!lol!name")).to eq "lol_name" - expect(Namespace.make_valid("Miquel.Sabate")).to eq "miquel.sabate" - expect(Namespace.make_valid("Miquel.Sabate.")).to eq "miquel.sabate" - expect(Namespace.make_valid("M")).to eq "m" - expect(Namespace.make_valid("_M_")).to eq "m" + expect(described_class.make_valid("_name")).to eq "name" + expect(described_class.make_valid("name_")).to eq "name" + expect(described_class.make_valid("___name_-aa__")).to eq "name_aa" + expect(described_class.make_valid("_ma._.n")).to eq "ma_n" + expect(described_class.make_valid("ma_s")).to eq "ma_s" + expect(described_class.make_valid("!lol!")).to eq "lol" + expect(described_class.make_valid("!lol!name")).to eq "lol_name" + expect(described_class.make_valid("Miquel.Sabate")).to eq "miquel.sabate" + expect(described_class.make_valid("Miquel.Sabate.")).to eq "miquel.sabate" + expect(described_class.make_valid("M")).to eq "m" + expect(described_class.make_valid("_M_")).to eq "m" end it "adds an increment if a team with the name already exists" do - expect(Namespace.make_valid(namespace.name)).to eq "#{namespace.name}0" + expect(described_class.make_valid(namespace.name)).to eq "#{namespace.name}0" create(:namespace, name: "#{namespace.name}0", team: team) - expect(Namespace.make_valid(namespace.name)).to eq "#{namespace.name}1" + expect(described_class.make_valid(namespace.name)).to eq "#{namespace.name}1" end end end diff --git a/spec/models/registry/auth_scope_spec.rb b/spec/models/registry/auth_scope_spec.rb index 6eeb68933..def35c808 100644 --- a/spec/models/registry/auth_scope_spec.rb +++ b/spec/models/registry/auth_scope_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe Registry::AuthScope, type: :model do diff --git a/spec/models/registry_spec.rb b/spec/models/registry_spec.rb index d9c1ce432..33998630c 100644 --- a/spec/models/registry_spec.rb +++ b/spec/models/registry_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: registries @@ -59,35 +61,6 @@ def get_tag_from_target_test(namespace, repo, mtype, digest, tag = nil) end end -# The mock client used by the RegistryReachable class. -class RegistryReachableClient < Registry - def initialize(constant, result) - @constant = constant - @result = result - end - - def reachable? - raise @constant unless @constant.nil? - @result - end -end - -# A Mock class for the Registry that provides a `client` method that returns an -# object that handles the `reachable?` method. -class RegistryReachable < Registry - attr_reader :use_ssl - - def initialize(constant, result, ssl) - @constant = constant - @result = result - @use_ssl = ssl - end - - def client - RegistryReachableClient.new(@constant, @result) - end -end - def create_empty_namespace owner = create(:user) team = create(:team, owners: [owner]) @@ -95,7 +68,7 @@ def create_empty_namespace end describe Registry, type: :model do - it { should have_many(:namespaces) } + it { is_expected.to have_many(:namespaces) } describe "after_create" do it "creates namespaces after_create" do @@ -136,21 +109,31 @@ def create_empty_namespace # rubocop: disable Metrics/LineLength describe "#reachable" do + after :each do + allow_any_instance_of(::Portus::RegistryClient).to receive(:perform_request).and_call_original + end + it "returns the proper message for each scenario" do + GOOD_RESPONSE = OpenStruct.new(code: 401) + [ - [nil, true, true, /^$/], - [nil, false, true, /registry does not implement v2/], - [SocketError, true, true, /The given registry is not available/], - [Errno::ETIMEDOUT, true, true, /connection timed out/], - [Net::OpenTimeout, true, true, /connection timed out/], - [Net::HTTPBadResponse, true, true, /wrong with your SSL configuration/], - [Net::HTTPBadResponse, true, false, /Error: not using SSL/], - [OpenSSL::SSL::SSLError, true, true, /SSL error while communicating with the registry, check the server logs for more details./], - [OpenSSL::SSL::SSLError, true, false, /SSL error while communicating with the registry, check the server logs for more details./], - [StandardError, true, true, /something went wrong/] + [nil, GOOD_RESPONSE, true, /^$/], + [nil, nil, true, /registry does not implement v2/], + [SocketError, GOOD_RESPONSE, true, /connection refused/], + [Errno::ECONNREFUSED, GOOD_RESPONSE, true, /connection refused/], + [Errno::ETIMEDOUT, GOOD_RESPONSE, true, /connection timed out/], + [Net::OpenTimeout, GOOD_RESPONSE, true, /connection timed out/], + [Net::HTTPBadResponse, GOOD_RESPONSE, true, /wrong with your SSL config/], + [OpenSSL::SSL::SSLError, GOOD_RESPONSE, true, /SSL error while communicating with the registry/], + [OpenSSL::SSL::SSLError, GOOD_RESPONSE, false, /SSL error while communicating with the registry/], + [StandardError, GOOD_RESPONSE, true, /something went wrong/] ].each do |cs| - rr = RegistryReachable.new(cs.first, cs[1], cs[2]) - expect(rr.reachable?).to match(cs.last) + allow_any_instance_of(::Portus::RegistryClient).to receive(:perform_request) do + raise cs.first if cs.first + cs[1] + end + r = Registry.new(hostname: "something", name: "test", use_ssl: cs[2]) + expect(r.reachable?).to match(cs.last) end end end @@ -182,9 +165,9 @@ def create_empty_namespace # Differentiate between global & local namespace ret = mock.get_tag_from_target_test(create_empty_namespace, - "busybox", - "application/vnd.docker.distribution.manifest.v2+json", - "sha:1234") + "busybox", + "application/vnd.docker.distribution.manifest.v2+json", + "sha:1234") expect(ret).to eq "latest" end @@ -216,9 +199,9 @@ def create_empty_namespace expect(Rails.logger).to receive(:info).with(/Reason: Some message/) ret = mock.get_tag_from_target_test(create_empty_namespace, - "busybox", - "application/vnd.docker.distribution.manifest.v2+json", - "sha:1234") + "busybox", + "application/vnd.docker.distribution.manifest.v2+json", + "sha:1234") expect(ret).to be_nil end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 94dc6c880..f19971759 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: repositories @@ -23,9 +25,9 @@ def get_url(repo, tag) end describe Repository do - it { should belong_to(:namespace) } - it { should have_many(:tags) } - it { should have_many(:stars) } + it { is_expected.to belong_to(:namespace) } + it { is_expected.to have_many(:tags) } + it { is_expected.to have_many(:stars) } describe "starrable behaviour" do let(:user) { create(:user) } @@ -33,18 +35,18 @@ def get_url(repo, tag) let(:star) { create(:star, user: user, repository: repository) } let(:other_user) { create(:user) } - it "should identify if it is already starred by a user" do + it "identifies if it is already starred by a user" do expect(star.repository.starred_by?(user)).to be true expect(star.repository.starred_by?(other_user)).to be false end - it "should be starrable by a user" do + it "is starrable by a user" do repository.toggle_star(user) expect(repository.starred_by?(user)).to be true expect(repository.starred_by?(other_user)).to be false end - it "should be unstarrable by a user" do + it "is unstarrable by a user" do repository = star.repository repository.toggle_star(user) expect(repository.starred_by?(user)).to be false @@ -78,7 +80,7 @@ def get_url(repo, tag) end let(:user) { create(:user) } - before :each do + before do VCR.turn_on! end @@ -88,49 +90,49 @@ def get_url(repo, tag) # First we create it, and make sure that it creates the activity. expect do - Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) + described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) end.to change(PublicActivity::Activity, :count).by(1) # And now it should create another activities. expect do - Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) + described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) end.to change(PublicActivity::Activity, :count).by(1) end it "updates the digest of an already existing tag" do event = { "actor" => { "name" => user.username }, "target" => { "digest" => "foo" } } - Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) - expect(Repository.find_by(name: repository_name).tags.first.digest).to eq("foo") + described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) + expect(described_class.find_by(name: repository_name).tags.first.digest).to eq("foo") # Making sure that the updated_at column is set in the past. - tag = Repository.find_by(name: repository_name).tags.first + tag = described_class.find_by(name: repository_name).tags.first tag.update_columns(updated_at: 2.hours.ago) ua = tag.updated_at event["target"]["digest"] = "bar" - Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) - tag = Repository.find_by(name: repository_name).tags.first + described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) + tag = described_class.find_by(name: repository_name).tags.first expect(tag.digest).to eq("bar") - expect(tag.updated_at).to_not eq(ua) + expect(tag.updated_at).not_to eq(ua) end it "updates the image id of an already existing tag" do - allow(Repository).to receive(:id_and_digest_from_event).and_return(["image_id", "foo"]) + allow(described_class).to receive(:id_and_digest_from_event).and_return(%w[image_id foo]) event = { "actor" => { "name" => user.username }, "target" => { "digest" => "foo" } } - Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) - expect(Repository.find_by(name: repository_name).tags.first.digest).to eq("foo") + described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) + expect(described_class.find_by(name: repository_name).tags.first.digest).to eq("foo") # Making sure that the updated_at column is set in the past. - tag = Repository.find_by(name: repository_name).tags.first + tag = described_class.find_by(name: repository_name).tags.first tag.update_columns(updated_at: 2.hours.ago) ua = tag.updated_at - allow(Repository).to receive(:id_and_digest_from_event).and_return(["id", "bar"]) - Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) - tag = Repository.find_by(name: repository_name).tags.first + allow(described_class).to receive(:id_and_digest_from_event).and_return(%w[id bar]) + described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) + tag = described_class.find_by(name: repository_name).tags.first expect(tag.image_id).to eq("id") expect(tag.digest).to eq("bar") - expect(tag.updated_at).to_not eq(ua) + expect(tag.updated_at).not_to eq(ua) end end @@ -146,14 +148,14 @@ def get_url(repo, tag) it "sends event to logger" do VCR.use_cassette("registry/get_image_manifest_webhook", record: :none) do expect do - Repository.handle_push_event(event) - end.to change(Repository, :count).by(0) + described_class.handle_push_event(event) + end.to change(described_class, :count).by(0) end end end context "event comes from an internally named registry" do - before :each do + before do @event = build(:raw_push_manifest_event).to_test_hash @event["target"]["repository"] = repository_name @event["target"]["url"] = get_url(repository_name, tag_name) @@ -165,8 +167,8 @@ def get_url(repo, tag) it "sends event to logger" do expect(Rails.logger).to receive(:info) expect do - Repository.handle_push_event(@event) - end.to change(Repository, :count).by(0) + described_class.handle_push_event(@event) + end.to change(described_class, :count).by(0) end it "finds an internal registry" do @@ -181,7 +183,7 @@ def get_url(repo, tag) end context "event comes from an externally named registry" do - before :each do + before do @event = build(:raw_push_manifest_event).to_test_hash @event["target"]["repository"] = repository_name @event["target"]["url"] = get_url(repository_name, tag_name) @@ -193,8 +195,8 @@ def get_url(repo, tag) it "sends event to logger" do expect(Rails.logger).to receive(:info) expect do - Repository.handle_push_event(@event) - end.to change(Repository, :count).by(0) + described_class.handle_push_event(@event) + end.to change(described_class, :count).by(0) end it "finds an external registry" do @@ -209,7 +211,7 @@ def get_url(repo, tag) end context "event comes from an unknown registry" do - before :each do + before do @event = build(:raw_push_manifest_event).to_test_hash @event["target"]["repository"] = repository_name @event["target"]["url"] = get_url(repository_name, tag_name) @@ -221,8 +223,8 @@ def get_url(repo, tag) it "sends event to logger" do expect(Rails.logger).to receive(:info) expect do - Repository.handle_push_event(@event) - end.to change(Repository, :count).by(0) + described_class.handle_push_event(@event) + end.to change(described_class, :count).by(0) end it "doesn't find any registry" do @@ -234,7 +236,7 @@ def get_url(repo, tag) end context "event comes from an unknown user" do - before :each do + before do @event = build(:raw_push_manifest_event).to_test_hash @event["target"]["repository"] = repository_name @event["target"]["url"] = get_url(repository_name, tag_name) @@ -245,14 +247,13 @@ def get_url(repo, tag) it "sends event to logger" do expect do - Repository.handle_push_event(@event) - end.to change(Repository, :count).by(0) + described_class.handle_push_event(@event) + end.to change(described_class, :count).by(0) end - end context "when dealing with a top level repository" do - before :each do + before do @event = build(:raw_push_manifest_event).to_test_hash @event["target"]["repository"] = repository_name @event["target"]["url"] = get_url(repository_name, "digest") @@ -263,16 +264,16 @@ def get_url(repo, tag) end context "when the repository is not known by Portus" do - it "should create repository and tag objects" do + it "creates repository and tag objects" do repository = nil VCR.use_cassette("registry/get_image_manifest_webhook", record: :none) do expect do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end.to change(Namespace, :count).by(0) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 1 expect(repository.namespace).to eq(registry.global_namespace) @@ -288,12 +289,12 @@ def get_url(repo, tag) VCR.use_cassette("registry/get_tags_list_webhook", record: :none) do expect do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end.to change(Namespace, :count).by(0) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 1 expect(repository.namespace).to eq(registry.global_namespace) @@ -307,7 +308,7 @@ def get_url(repo, tag) repository = nil VCR.use_cassette("registry/get_image_manifest_webhook", record: :none) do expect do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end.to change(PublicActivity::Activity, :count).by(1) end @@ -321,22 +322,22 @@ def get_url(repo, tag) end context "when a new version of an already known repository" do - before :each do + before do repository = create(:repository, name: repository_name, namespace: registry.global_namespace) repository.tags << Tag.new(name: "1.0.0") end - it "should create a new tag" do + it "creates a new tag" do repository = nil VCR.use_cassette("registry/get_image_manifest_webhook", record: :none) do expect do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end.to change(Namespace, :count).by(0) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 2 expect(repository.namespace).to eq(registry.global_namespace) @@ -350,7 +351,7 @@ def get_url(repo, tag) repository = nil VCR.use_cassette("registry/get_image_manifest_webhook", record: :none) do expect do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end.to change(PublicActivity::Activity, :count).by(1) end @@ -367,7 +368,7 @@ def get_url(repo, tag) let(:repository_namespaced_name) { "portus/busybox" } let(:admin) { create(:admin) } - before :each do + before do team_user = create(:team, owners: [admin]) @ns = create(:namespace, name: "portus", team: team_user, registry: registry) create(:repository, name: "busybox", namespace: registry.global_namespace) @@ -378,10 +379,10 @@ def get_url(repo, tag) event["target"]["repository"] = repository_namespaced_name event["target"]["url"] = get_url(repository_namespaced_name, tag_name) VCR.use_cassette("registry/get_image_manifest_another_webhook", record: :none) do - Repository.handle_push_event(event) + described_class.handle_push_event(event) end - repos = Repository.all.order(id: :asc) + repos = described_class.all.order(id: :asc) expect(repos.count).to be(2) expect(repos.first.namespace.id).to be(registry.global_namespace.id) expect(repos.last.namespace.id).to be(@ns.id) @@ -393,7 +394,7 @@ def get_url(repo, tag) let(:namespace_name) { "suse" } let(:digest) { "digest" } - before :each do + before do name = "#{namespace_name}/#{repository_name}" @event = build(:raw_push_manifest_event).to_test_hash @@ -407,25 +408,25 @@ def get_url(repo, tag) context "when the namespace is not known by Portus" do it "does not create the namespace" do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) expect(repository).to be_nil end end context "when the namespace is known by Portus" do - before :each do + before do @namespace = create(:namespace, name: namespace_name, registry: registry) end - it "should create repository and tag objects when the repository is unknown to portus" do + it "creates repository and tag objects when the repository is unknown to portus" do repository = nil VCR.use_cassette("registry/get_image_manifest_namespaced_webhook", record: :none) do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 1 expect(repository.namespace.name).to eq(namespace_name) @@ -436,17 +437,17 @@ def get_url(repo, tag) expect(repository.tags.find_by(name: tag_name).author).to eq(user) end - it "should create a new tag when the repository is already known to portus" do + it "creates a new tag when the repository is already known to portus" do repository = create(:repository, name: repository_name, namespace: @namespace) repository.tags << Tag.new(name: "1.0.0") VCR.use_cassette("registry/get_image_manifest_namespaced_webhook", record: :none) do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 2 expect(repository.namespace.name).to eq(namespace_name) @@ -462,13 +463,13 @@ def get_url(repo, tag) repository = nil VCR.use_cassette("registry/get_image_manifest_namespaced_webhook_v2", record: :none) do expect do - repository = Repository.handle_push_event(@event) - end.to change(Repository, :count).by(1) + repository = described_class.handle_push_event(@event) + end.to change(described_class, :count).by(1) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 1 expect(repository.namespace.name).to eq(namespace_name) @@ -485,12 +486,12 @@ def get_url(repo, tag) repository.tags << Tag.new(name: "1.0.0") VCR.use_cassette("registry/get_image_manifest_namespaced_webhook_v2", record: :none) do - repository = Repository.handle_push_event(@event) + repository = described_class.handle_push_event(@event) end expect(repository).not_to be_nil - expect(Repository.count).to eq 1 - expect(Repository.count).to eq 1 + expect(described_class.count).to eq 1 + expect(described_class.count).to eq 1 expect(Tag.count).to eq 2 expect(repository.namespace.name).to eq(namespace_name) @@ -515,35 +516,35 @@ def get_url(repo, tag) let!(:tag2) { create(:tag, name: "tag2", repository: repo2) } let!(:tag3) { create(:tag, name: "tag3", repository: repo2) } - before :each do + before do # Even if the returned value is dummy, we want to make sure that the # given arguments are set accordingly. The checked values are basically # hardcoded, which shouldn't be a problem since there are not a lot of # tests anyways. allow_any_instance_of(Portus::RegistryClient).to receive(:manifest) do |_, *args| if args.first != "busybox" && !args.first.include?("/") - raise "Should be included inside of a namespace" + raise ::Portus::RegistryClient::ManifestError, "Should be included inside of a namespace" end if args.last != "latest" && args.last != "0.1" && args.last != "tag1" - raise "Using an unknown tag" + raise ::Portus::RegistryClient::ManifestError, "Using an unknown tag" end ["id", "digest", ""] end - allow(Repository).to receive(:id_and_digest_from_event).and_return(["id", "digest"]) + allow(described_class).to receive(:id_and_digest_from_event).and_return(%w[id digest]) end it "adds and deletes tags accordingly" do # Update existing tag's digest repo = { "name" => "#{namespace.name}/repo1", "tags" => ["tag1"] } - repo = Repository.create_or_update!(repo) + repo = described_class.create_or_update!(repo) expect(repo.id).to eq repo1.id expect(repo.tags.find_by(name: "tag1").digest).to match("digest") # Removes the existing tag and adds two. repo = { "name" => "#{namespace.name}/repo1", "tags" => ["latest", "0.1"] } - repo = Repository.create_or_update!(repo) + repo = described_class.create_or_update!(repo) expect(repo.id).to eq repo1.id expect(repo.tags.map(&:name).sort).to match_array(["0.1", "latest"]) @@ -555,33 +556,33 @@ def get_url(repo, tag) # Just adds a new tag. repo = { "name" => "#{namespace.name}/repo2", "tags" => ["latest", tag2.name, tag3.name] } - repo = Repository.create_or_update!(repo) + repo = described_class.create_or_update!(repo) expect(repo.id).to eq repo2.id ary = [tag2.name, tag3.name, "latest"].sort expect(repo.tags.map(&:name).sort).to match_array(ary) # Create repo and tags. repo = { "name" => "busybox", "tags" => ["latest", "0.1"] } - repo = Repository.create_or_update!(repo) + repo = described_class.create_or_update!(repo) expect(repo.name).to eq "busybox" expect(repo.tags.map(&:name).sort).to match_array(["0.1", "latest"]) expect(repo.tags.map(&:digest).uniq).to match_array(["digest"]) # Trying to create a repo into an unknown namespace. repo = { "name" => "unknown/repo1", "tags" => ["latest", "0.1"] } - expect(Repository.create_or_update!(repo)).to be_nil + expect(described_class.create_or_update!(repo)).to be_nil end it "doesn't remove tags of same name for different repo" do # create "latest" for repo1 and repo2 event_one = { "name" => "#{namespace.name}/repo1", "tags" => ["latest"] } - Repository.create_or_update!(event_one) + described_class.create_or_update!(event_one) event_two = { "name" => "#{namespace.name}/repo2", "tags" => ["latest"] } - Repository.create_or_update!(event_two) + described_class.create_or_update!(event_two) # remove "latest" for repo2 event_three = { "name" => "#{namespace.name}/repo2", "tags" => ["other"] } - Repository.create_or_update!(event_three) + described_class.create_or_update!(event_three) expect(repo1.tags.pluck(:name)).to include("latest") expect(repo2.tags.pluck(:name)).not_to include("latest") @@ -651,8 +652,8 @@ def get_url(repo, tag) end it "doesn't do anything for a non-existing tag" do - Repository.handle_delete_event(event) - expect(Repository.count).to eq 1 + described_class.handle_delete_event(event) + expect(described_class.count).to eq 1 expect(Tag.count).to eq 3 end @@ -662,8 +663,8 @@ def get_url(repo, tag) another["target"]["digest"] = tag1.digest another["target"]["repository"] = "unknown" - Repository.handle_delete_event(another) - expect(Repository.count).to eq 1 + described_class.handle_delete_event(another) + expect(described_class.count).to eq 1 expect(Tag.count).to eq 3 end @@ -671,14 +672,14 @@ def get_url(repo, tag) another = event.dup another["target"]["digest"] = tag1.digest - Repository.handle_delete_event(another) - expect(Repository.count).to eq 1 + described_class.handle_delete_event(another) + expect(described_class.count).to eq 1 expect(Tag.count).to eq 1 # 2 were deleted because there was a re-tag another["target"]["digest"] = tag3.digest - Repository.handle_delete_event(another) - expect(Repository.count).to eq 0 + described_class.handle_delete_event(another) + expect(described_class.count).to eq 0 expect(Tag.count).to eq 0 end end @@ -695,12 +696,12 @@ def get_url(repo, tag) # First we create it, and make sure that it creates the activity. repo = nil expect do - repo = Repository.add_repo(event, registry.global_namespace, repository_name, tag_name) + repo = described_class.add_repo(event, registry.global_namespace, repository_name, tag_name) end.to change(PublicActivity::Activity, :count).by(1) activity = PublicActivity::Activity.first expect(activity.trackable_type).to eq "Repository" - expect(activity.trackable_id).to eq Repository.first.id + expect(activity.trackable_id).to eq described_class.first.id expect(activity.key).to eq "repository.push" expect(activity.owner_id).to eq user.id expect(activity.parameters).to be_empty @@ -729,7 +730,7 @@ def get_url(repo, tag) namespace_name: registry.global_namespace.clean_name) # Of course, the repo should be removed - expect(Repository.count).to eq 0 + expect(described_class.count).to eq 0 end end end diff --git a/spec/models/star_spec.rb b/spec/models/star_spec.rb index ed7c41387..dfd1924ab 100644 --- a/spec/models/star_spec.rb +++ b/spec/models/star_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: stars @@ -17,9 +19,8 @@ require "rails_helper" describe Star do - - it { should belong_to(:repository) } - it { should belong_to(:user) } + it { is_expected.to belong_to(:repository) } + it { is_expected.to belong_to(:user) } it "validates that a user does not star the same repository twice" do author = create(:user) @@ -30,5 +31,4 @@ FactoryGirl.create(:star, user: author, repository: repository) end.to raise_error(ActiveRecord::RecordInvalid) end - end diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb index b495dd307..2e260d394 100644 --- a/spec/models/tag_spec.rb +++ b/spec/models/tag_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: tags @@ -36,18 +38,18 @@ def fetch_digest_test let!(:user) { create(:admin) } let!(:repository) { create(:repository, namespace: registry.global_namespace, name: "repo") } - it { should belong_to(:repository) } - it { should belong_to(:author) } + it { is_expected.to belong_to(:repository) } + it { is_expected.to belong_to(:author) } describe "creating tags" do it "defaults to latest" do - t = Tag.create(repository: repository) + t = described_class.create(repository: repository) expect(t.name).to eq("latest") end it "does not accept nil names" do expect do - Tag.create(name: nil, repository: repository) + described_class.create(name: nil, repository: repository) end.to raise_error(ActiveRecord::StatementInvalid) end @@ -71,7 +73,7 @@ def fetch_digest_test let!(:tag2) { create(:tag, name: "tag2", repository: repository, digest: "2") } it "returns false if there is no digest" do - allow_any_instance_of(Tag).to receive(:fetch_digest).and_return(nil) + allow_any_instance_of(described_class).to receive(:fetch_digest).and_return(nil) expect(tag.delete_by_digest!(user)).to be_falsey end @@ -82,7 +84,7 @@ def fetch_digest_test # That being said, the tag should be "marked". expect(tag.delete_by_digest!(user)).to be_falsey - expect(tag.reload.marked?).to be_truthy + expect(tag.reload).to be_marked end it "deletes the tag and updates corresponding activities" do @@ -147,7 +149,7 @@ def fetch_digest_test tag.delete_by_digest!(user) - expect(Tag.find_by(name: "t")).to be_nil + expect(described_class.find_by(name: "t")).to be_nil end end @@ -156,7 +158,7 @@ def fetch_digest_test describe "#delete_and_update!" do let!(:tag) { create(:tag, name: "tag1", repository: repository, digest: "1") } - before :each do + before do tag.destroy end @@ -213,7 +215,8 @@ def fetch_digest_test it "returns nil if security scanning is not enabled" do # Checking that even if scanning is done and there are vulnerabilities, it # returns nil because security scanning is disabled. - tag.update_columns(scanned: Tag.statuses[:scan_done], vulnerabilities: "something") + tag.update_columns(scanned: described_class.statuses[:scan_done], + vulnerabilities: "something") expect(tag.fetch_vulnerabilities).to be_nil end @@ -225,13 +228,14 @@ def fetch_digest_test it "returns nil if scan is work in progress" do enable_security_vulns_module! - tag.update_columns(scanned: Tag.statuses[:scan_working]) + tag.update_columns(scanned: described_class.statuses[:scan_working]) expect(tag.fetch_vulnerabilities).to be_nil end it "returns the vulnerabilities when scan is over" do enable_security_vulns_module! - tag.update_columns(scanned: Tag.statuses[:scan_done], vulnerabilities: "something") + tag.update_columns(scanned: described_class.statuses[:scan_done], + vulnerabilities: "something") expect(tag.fetch_vulnerabilities).to eq "something" end end diff --git a/spec/models/team_spec.rb b/spec/models/team_spec.rb index 78a4286dd..ac10fb8b3 100644 --- a/spec/models/team_spec.rb +++ b/spec/models/team_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: teams @@ -17,9 +19,9 @@ require "rails_helper" describe Team do - it { should validate_presence_of(:name) } - it { should validate_presence_of(:owners) } - it { should have_many(:namespaces) } + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to validate_presence_of(:owners) } + it { is_expected.to have_many(:namespaces) } it "does not check whether the given name is downcased or not" do # Does not check name case because: @@ -33,35 +35,35 @@ # The registry does not count. # NOTE: the registry factory also creates a user. create(:registry) - expect(Team.all_non_special).to be_empty - expect(Team.count).to be(2) + expect(described_class.all_non_special).to be_empty + expect(described_class.count).to be(2) # Creating a proper team, this counts. create(:team, owners: [User.first]) - expect(Team.all_non_special.count).to be(1) - expect(Team.count).to be(3) + expect(described_class.all_non_special.count).to be(1) + expect(described_class.count).to be(3) # Personal namespaces don't count. create(:user) - expect(Team.all_non_special.count).to be(1) - expect(Team.count).to be(4) + expect(described_class.all_non_special.count).to be(1) + expect(described_class.count).to be(4) end describe "make_valid" do it "does nothing if there's no team with the name" do name = "something" - expect(Team.make_valid(name)).to eq name + expect(described_class.make_valid(name)).to eq name end it "adds an increment if a team with the name already exists" do name = "something" create(:team, name: name) - expect(Team.make_valid(name)).to eq "#{name}0" + expect(described_class.make_valid(name)).to eq "#{name}0" create(:team, name: "#{name}0") - expect(Team.make_valid(name)).to eq "#{name}1" + expect(described_class.make_valid(name)).to eq "#{name}1" end end end diff --git a/spec/models/team_user_spec.rb b/spec/models/team_user_spec.rb index a66e649dc..30b5c03da 100644 --- a/spec/models/team_user_spec.rb +++ b/spec/models/team_user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: team_users @@ -49,8 +51,8 @@ end it "checks whether it's the only owner or not" do - expect(team.team_users.first.only_owner?).to be_falsey + expect(team.team_users.first).not_to be_only_owner team1 = create(:team, owners: [user1]) - expect(team1.team_users.first.only_owner?).to be_truthy + expect(team1.team_users.first).to be_only_owner end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 1d2a29d7a..127ca3f97 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: users @@ -40,9 +42,9 @@ describe User do subject { create(:user) } - it { should validate_uniqueness_of(:email) } - it { should validate_uniqueness_of(:username) } - it { should allow_value("test1", "1test").for(:username) } + it { is_expected.to validate_uniqueness_of(:email) } + it { is_expected.to validate_uniqueness_of(:username) } + it { is_expected.to allow_value("test1", "1test").for(:username) } describe "#private_namespace_and_team_available" do it "adds an error if the username cannot produce a valid namespace" do @@ -81,7 +83,7 @@ user2 = create(:user, username: "test") namespace = Namespace.find_by(name: "test") - expect(namespace).to_not be nil + expect(namespace).not_to be nil expect(user2.namespace.id).to eq namespace.id end @@ -91,13 +93,13 @@ it "find user by username" do APP_CONFIG["ldap"] = { "enabled" => false } event = { "actor" => { "name" => "username001" } } - expect(User.find_from_event(event)).not_to be_nil + expect(described_class.find_from_event(event)).not_to be_nil end end describe "#create_personal_namespace!" do context "no registry defined yet" do - before :each do + before do expect(Registry.count).to be(0) end @@ -107,11 +109,10 @@ expect(Team.find_by(name: subject.username)).to be(nil) expect(Namespace.find_by(name: subject.username)).to be(nil) end - end context "registry defined" do - before :each do + before do create(:admin) create(:registry) end @@ -138,7 +139,7 @@ let!(:admin2) { create(:admin, enabled: false) } it "computes the right amount of admin users" do - admins = User.admins + admins = described_class.admins expect(admins.count).to be 1 expect(admins.first.id).to be admin1.id end @@ -150,7 +151,7 @@ it "Toggles the admin attribute" do # We have a registry and the admin user is the owner. - admin = User.where(admin: true).first + admin = described_class.where(admin: true).first owners = registry.global_namespace.team.owners expect(owners.count).to be(1) expect(owners.first.id).to be(admin.id) diff --git a/spec/models/webhook_delivery_spec.rb b/spec/models/webhook_delivery_spec.rb index 26392e4c9..2e3791790 100644 --- a/spec/models/webhook_delivery_spec.rb +++ b/spec/models/webhook_delivery_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_deliveries @@ -24,8 +26,8 @@ RSpec.describe WebhookDelivery, type: :model do subject { create(:webhook_delivery, webhook: create(:webhook)) } - it { should belong_to(:webhook) } - it { should validate_uniqueness_of(:uuid).scoped_to(:webhook_id) } + it { is_expected.to belong_to(:webhook) } + it { is_expected.to validate_uniqueness_of(:uuid).scoped_to(:webhook_id) } describe "success?" do let!(:registry) { create(:registry) } @@ -59,7 +61,7 @@ create(:webhook_header, webhook: webhook_noauth, name: "foo", value: "bar") end - before :each do + before do stub_request(:POST, "username:password@www.example.com") .to_return( status: 200, @@ -73,7 +75,7 @@ ) end - it "should resend HTTP requests" do + it "resends HTTP requests" do create :webhook_delivery, webhook: webhook_auth create :webhook_delivery, webhook: webhook_noauth WebhookDelivery.find_each do |delivery| diff --git a/spec/models/webhook_header_spec.rb b/spec/models/webhook_header_spec.rb index add01db60..c2db3aa5e 100644 --- a/spec/models/webhook_header_spec.rb +++ b/spec/models/webhook_header_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhook_headers @@ -20,6 +22,6 @@ RSpec.describe WebhookHeader, type: :model do subject { create(:webhook_header, webhook: create(:webhook)) } - it { should belong_to(:webhook) } - it { should validate_uniqueness_of(:name).scoped_to(:webhook_id) } + it { is_expected.to belong_to(:webhook) } + it { is_expected.to validate_uniqueness_of(:name).scoped_to(:webhook_id) } end diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb index dfdbc632d..297070e75 100644 --- a/spec/models/webhook_spec.rb +++ b/spec/models/webhook_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: webhooks @@ -22,19 +24,20 @@ RSpec.describe Webhook, type: :model do subject { create(:webhook, namespace: create(:namespace)) } - let!(:request_methods) { ["GET", "POST"] } + + let!(:request_methods) { %w[GET POST] } let!(:content_types) { ["application/json", "application/x-www-form-urlencoded"] } - it { should have_many(:headers) } - it { should have_many(:deliveries) } - it { should belong_to(:namespace) } + it { is_expected.to have_many(:headers) } + it { is_expected.to have_many(:deliveries) } + it { is_expected.to belong_to(:namespace) } - it { should validate_presence_of(:url) } - it { should_not allow_value("won't work").for(:url) } - it { should define_enum_for(:request_method) } - it { should allow_value(*request_methods).for(:request_method) } - it { should define_enum_for(:content_type) } - it { should allow_value(*content_types).for(:content_type) } + it { is_expected.to validate_presence_of(:url) } + it { is_expected.not_to allow_value("won't work").for(:url) } + it { is_expected.to define_enum_for(:request_method) } + it { is_expected.to allow_value(*request_methods).for(:request_method) } + it { is_expected.to define_enum_for(:content_type) } + it { is_expected.to allow_value(*content_types).for(:content_type) } describe "push and delete events" do let!(:registry) { create(:registry) } @@ -49,7 +52,7 @@ } end - before :each do + before do stub_request(:POST, "username:password@www.example.com") .to_return(status: 200) stub_request(:POST, "www.example.com").to_return(status: 200) @@ -64,7 +67,7 @@ create(:webhook_header, webhook: webhook_auth, name: "foo", value: "bar") end - it "should work when given user credentials" do + it "works when given user credentials" do Webhook.handle_push_event(event) delivery = WebhookDelivery.find_by(webhook: webhook_auth) expect(delivery.status).to eq 200 @@ -76,7 +79,7 @@ expect(JSON.parse(delivery.request_body)).to eq event end - it "should work when providing no user credentials" do + it "works when providing no user credentials" do Webhook.handle_push_event(event) delivery = WebhookDelivery.find_by(webhook: webhook_noauth) expect(delivery.status).to eq 200 @@ -88,14 +91,14 @@ expect(JSON.parse(delivery.request_body)).to eq event end - it "should fail in the given namespace cannot be found" do + it "fails in the given namespace cannot be found" do event["target"]["repository"] = "unknown_namespace/unknown_repo" expect(Webhook.handle_push_event(event)).to be nil expect(Webhook.handle_delete_event(event)).to be nil end end - it "should skip disabled webhooks" do + it "skips disabled webhooks" do Webhook.handle_push_event(event) expect(WebhookDelivery.all).to be_empty diff --git a/spec/policies/namespace_policy_spec.rb b/spec/policies/namespace_policy_spec.rb index 542d73126..5bc44b7d7 100644 --- a/spec/policies/namespace_policy_spec.rb +++ b/spec/policies/namespace_policy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe NamespacePolicy do @@ -23,7 +25,7 @@ ) end - before :each do + before do @admin = create(:admin) end @@ -41,7 +43,7 @@ end it "disallows access to user who is not part of the team" do - expect(subject).to_not permit(user, namespace) + expect(subject).not_to permit(user, namespace) end it "allows access to any user if the namespace is public" do @@ -86,7 +88,7 @@ permissions :push? do it "disallow access to user with viewer role" do - expect(subject).to_not permit(viewer, namespace) + expect(subject).not_to permit(viewer, namespace) end it "allows access to user with contributor role" do @@ -98,7 +100,7 @@ end it "disallows access to user who is not part of the team" do - expect(subject).to_not permit(user, namespace) + expect(subject).not_to permit(user, namespace) end it "disallows access to user who is not logged in" do @@ -120,7 +122,7 @@ permissions :all? do it "disallow access to user with viewer role" do - expect(subject).to_not permit(viewer, namespace) + expect(subject).not_to permit(viewer, namespace) end it "allows access to user with contributor role" do @@ -132,7 +134,7 @@ end it "disallows access to user who is not part of the team" do - expect(subject).to_not permit(user, namespace) + expect(subject).not_to permit(user, namespace) end context "global namespace" do @@ -152,15 +154,15 @@ end it "disallows access to user who is not part of the team" do - expect(subject).to_not permit(user, namespace) + expect(subject).not_to permit(user, namespace) end it "disallow access to user with viewer role" do - expect(subject).to_not permit(viewer, namespace) + expect(subject).not_to permit(viewer, namespace) end it "disallow access to user with contributor role" do - expect(subject).to_not permit(contributor, namespace) + expect(subject).not_to permit(contributor, namespace) end it "disallows access to user who is not logged in" do @@ -177,13 +179,13 @@ end it "disallows access to everyone normal users" do - expect(subject).to_not permit(user, namespace) + expect(subject).not_to permit(user, namespace) end end end describe "scope" do - before :each do + before do # force creation of namespace namespace end diff --git a/spec/policies/public_activity/activity_policy_spec.rb b/spec/policies/public_activity/activity_policy_spec.rb index 6406cde74..2719731ec 100644 --- a/spec/policies/public_activity/activity_policy_spec.rb +++ b/spec/policies/public_activity/activity_policy_spec.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + require "rails_helper" describe PublicActivity::ActivityPolicy do + subject { described_class } let(:user) { create(:user) } let(:another_user) { create(:user) } @@ -14,8 +17,6 @@ let(:tag) { create(:tag, repository: repository) } let(:webhook) { create(:webhook, namespace: namespace, url: "http://example.com") } - subject { described_class } - describe "scope" do it "returns pertinent team activities" do activities = [ @@ -70,15 +71,15 @@ namespace2 = create(:namespace, registry: registry, team: create(:team, - owners: [another_user])) + owners: [another_user])) private_tag = create(:tag, repository: create(:repository, namespace: namespace2)) public_namespace = create(:namespace, registry: registry, visibility: Namespace.visibilities[:visibility_public], team: create(:team, - owners: [another_user], - namespaces: [namespace2])) + owners: [another_user], + namespaces: [namespace2])) public_tag = create(:tag, repository: create(:repository, namespace: public_namespace)) activities = [ diff --git a/spec/policies/registry_policy_spec.rb b/spec/policies/registry_policy_spec.rb index 60046457d..0b58c4660 100644 --- a/spec/policies/registry_policy_spec.rb +++ b/spec/policies/registry_policy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe RegistryPolicy do @@ -12,7 +14,7 @@ end it "does not allow access to regular users" do - expect(subject).to_not permit(user, nil) + expect(subject).not_to permit(user, nil) end end end diff --git a/spec/policies/repository_policy_spec.rb b/spec/policies/repository_policy_spec.rb index 6bf382528..9eb5acb02 100644 --- a/spec/policies/repository_policy_spec.rb +++ b/spec/policies/repository_policy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe RepositoryPolicy do @@ -10,7 +12,7 @@ let(:team2) { create(:team, owners: [user2]) } permissions :show? do - before :each do + before do public_namespace = create( :namespace, team: team2, @@ -54,7 +56,7 @@ end it "denies access if repository is private and the user is no team member or an admin" do - expect(subject).to_not permit(user, @private_repository) + expect(subject).not_to permit(user, @private_repository) end context "Anonymous users" do @@ -63,13 +65,13 @@ end it "does not grant access if the namespace is private and the user is anonymous" do - expect(subject).to_not permit(nil, @private_repository) + expect(subject).not_to permit(nil, @private_repository) end end end permissions :destroy? do - before :each do + before do public_namespace = create( :namespace, team: team2, @@ -99,28 +101,28 @@ end it "denies access if the namespace is public" do - expect(subject).to_not permit(user, @public_repository) + expect(subject).not_to permit(user, @public_repository) end it "denies access if the namespace is protected" do - expect(subject).to_not permit(user, @protected_repository) + expect(subject).not_to permit(user, @protected_repository) end it "grants access if the repository belongs to a namespace of a team member" do user3 = create(:user) TeamUser.create(team: team2, user: user3, role: TeamUser.roles["viewer"]) - expect(subject).to_not permit(user3, @private_repository) + expect(subject).not_to permit(user3, @private_repository) TeamUser.find_by(team: team2, user: user3).update_attributes(role: TeamUser.roles["owner"]) expect(subject).to permit(user3, @private_repository) end it "denies access if repository is private and the user is no team member or an admin" do - expect(subject).to_not permit(user, @private_repository) + expect(subject).not_to permit(user, @private_repository) end end describe "scope" do - before :each do + before do public_namespace = create( :namespace, team: team2, diff --git a/spec/policies/team_policy_spec.rb b/spec/policies/team_policy_spec.rb index d7b542942..68eb0a843 100644 --- a/spec/policies/team_policy_spec.rb +++ b/spec/policies/team_policy_spec.rb @@ -1,21 +1,21 @@ +# frozen_string_literal: true + require "spec_helper" describe TeamPolicy do - subject { described_class } let(:member) { create(:user) } let(:team) { create(:team, owners: [member]) } - before :each do + before do @admin = create(:admin) create(:registry) end permissions :member? do - it "denies access to a user who is not part of the team" do - expect(subject).to_not permit(create(:user), team) + expect(subject).not_to permit(create(:user), team) end it "allows access to a member of the team" do @@ -25,7 +25,6 @@ it "allows access to an admin even if he is not part of the team" do expect(subject).to permit(@admin, team) end - end describe "scope" do @@ -43,5 +42,4 @@ expect(Pundit.policy_scope(user, Team).to_a).to be_empty end end - end diff --git a/spec/policies/team_user_policy_spec.rb b/spec/policies/team_user_policy_spec.rb index 2cd11ca20..4f541488e 100644 --- a/spec/policies/team_user_policy_spec.rb +++ b/spec/policies/team_user_policy_spec.rb @@ -1,7 +1,8 @@ +# frozen_string_literal: true + require "rails_helper" describe TeamUserPolicy do - subject { described_class } let(:admin) { create(:admin) } @@ -18,13 +19,12 @@ let(:team_user) { TeamUser.new(team: team) } permissions :owner? do - it "denies access to a member of the team with viewer role" do - expect(subject).to_not permit(viewer, team_user) + expect(subject).not_to permit(viewer, team_user) end it "denies access to a member of the team with contributo role" do - expect(subject).to_not permit(contributor, team_user) + expect(subject).not_to permit(contributor, team_user) end it "allows access to a member of the team with owner role" do @@ -33,13 +33,11 @@ it "denies access to an owner of another group" do create(:team, owners: [user]) - expect(subject).to_not permit(user, team_user) + expect(subject).not_to permit(user, team_user) end it "allows access to admin user even if he is not part of the team" do expect(subject).to permit(admin, team_user) end - end - end diff --git a/spec/policies/webhook_policy_spec.rb b/spec/policies/webhook_policy_spec.rb index 5c0d211d7..3fd3405a3 100644 --- a/spec/policies/webhook_policy_spec.rb +++ b/spec/policies/webhook_policy_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe WebhookPolicy do @@ -23,7 +25,7 @@ end let(:webhook) { create(:webhook, namespace: namespace) } - before :each do + before do @admin = create(:admin) @registry = create(:registry) end @@ -38,20 +40,20 @@ end it "disallows contributor to change it" do - expect(subject).to_not permit(contributor, webhook) + expect(subject).not_to permit(contributor, webhook) end it "disallows user to change it" do - expect(subject).to_not permit(user, webhook) + expect(subject).not_to permit(user, webhook) end it "disallows viewer to change it" do - expect(subject).to_not permit(viewer, webhook) + expect(subject).not_to permit(viewer, webhook) end end describe "scope" do - before :each do + before do webhook end @@ -78,7 +80,7 @@ it "does show webhooks to user when appropiate" do expect(Pundit.policy_scope(user, Webhook).to_a).to be_empty create(:webhook, namespace: user.namespace) - expect(Pundit.policy_scope(user, Webhook).to_a).to_not be_empty + expect(Pundit.policy_scope(user, Webhook).to_a).not_to be_empty end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 2e4c26285..f2128759d 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + ENV["RAILS_ENV"] ||= "test" ENV["NODE_ENV"] ||= "test" @@ -46,7 +48,7 @@ def fake_authenticate! config.infer_base_class_for_anonymous_controllers = true # By default, LDAP will be faked away. - config.before :each do + config.before do allow_any_instance_of(Portus::LDAP).to receive(:authenticate!).and_return(:fake_authenticate!) end end diff --git a/spec/routing/namespaces_routing_spec.rb b/spec/routing/namespaces_routing_spec.rb index 6808e36df..276ad4afc 100644 --- a/spec/routing/namespaces_routing_spec.rb +++ b/spec/routing/namespaces_routing_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: namespaces diff --git a/spec/routing/repositories_routing_spec.rb b/spec/routing/repositories_routing_spec.rb index c0b3db136..b26b913da 100644 --- a/spec/routing/repositories_routing_spec.rb +++ b/spec/routing/repositories_routing_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # == Schema Information # # Table name: repositories diff --git a/spec/services/namespaces/build_service_spec.rb b/spec/services/namespaces/build_service_spec.rb index 7238e938d..db055dfa2 100644 --- a/spec/services/namespaces/build_service_spec.rb +++ b/spec/services/namespaces/build_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "Namespaces::CreateService" do @@ -11,7 +13,7 @@ it "builds a new namespace object" do namespace = service.execute - expect(namespace.persisted?).to be_falsey + expect(namespace).not_to be_persisted end end diff --git a/spec/services/namespaces/create_service_spec.rb b/spec/services/namespaces/create_service_spec.rb index faf32f237..7671c3e05 100644 --- a/spec/services/namespaces/create_service_spec.rb +++ b/spec/services/namespaces/create_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "Namespaces::CreateService" do diff --git a/spec/services/registries/validate_service_spec.rb b/spec/services/registries/validate_service_spec.rb index 58b86c82c..aec2d1061 100644 --- a/spec/services/registries/validate_service_spec.rb +++ b/spec/services/registries/validate_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "Registries::ValidateService" do diff --git a/spec/services/teams/create_service_spec.rb b/spec/services/teams/create_service_spec.rb index c85dfc688..b450b9e53 100644 --- a/spec/services/teams/create_service_spec.rb +++ b/spec/services/teams/create_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "Teams::CreateService" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 698378cdf..b6ce611b5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "codeclimate-test-reporter" CodeClimate::TestReporter.start @@ -34,7 +36,7 @@ # Some tests use Timecop, just make sure that everything is as expected # after returning from it. - config.before :each do + config.before do Timecop.return # Clear the global config before each test. diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 3492c5228..0c0a7ac9e 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "capybara/rails" require "capybara/rspec" require "capybara/poltergeist" diff --git a/spec/support/connection.rb b/spec/support/connection.rb index 6883d8b9b..4f05a2c08 100644 --- a/spec/support/connection.rb +++ b/spec/support/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # HACK: PostgreSQL has exactly one test failing randomly because of a # `PG::ConnectionBad` exception. We've tried several alternatives but none of # them worked. So, instead, this piece of code will try the connection up again @@ -10,10 +12,9 @@ if defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) module ActiveRecord::ConnectionAdapters + # Re-opening PostgreSQLAdapter to add the new reconnect! method. class PostgreSQLAdapter - # rubocop:disable Style/Alias - alias_method :reconnect_without_retry!, :reconnect! - # rubocop:enable Style/Alias + alias reconnect_without_retry! reconnect! attr_accessor :portus_retries @@ -36,4 +37,5 @@ def reconnect!(*args) end end end + # rubocop:enable Style/ClassAndModuleChildren end diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb index a2c58fa7e..b471e54be 100644 --- a/spec/support/database_cleaner.rb +++ b/spec/support/database_cleaner.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + require "database_cleaner" # DatabaseCleaner has been configured like this: @@ -21,7 +23,7 @@ end end - config.before(:each) do + config.before do DatabaseCleaner.strategy = :transaction end @@ -29,11 +31,11 @@ DatabaseCleaner.strategy = :truncation end - config.before(:each) do + config.before do DatabaseCleaner.start end - config.after(:each) do + config.after do DatabaseCleaner.clean end end diff --git a/spec/support/devise.rb b/spec/support/devise.rb index 1b8ba95c1..e8b2b1a24 100644 --- a/spec/support/devise.rb +++ b/spec/support/devise.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # Setup devise for tests. RSpec.configure do |config| config.include Devise::TestHelpers, type: :controller diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index 8163193db..2baa2b3ba 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # A simple module containing some helper methods for acceptance tests. module Helpers # Login the given user and visit the root url. diff --git a/spec/support/models/registry_raw_event.rb b/spec/support/models/registry_raw_event.rb index dff16319c..0271d956d 100644 --- a/spec/support/models/registry_raw_event.rb +++ b/spec/support/models/registry_raw_event.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RegistryRawEvent attr_accessor :action, :target, :request, :actor diff --git a/spec/support/wait_for_events.rb b/spec/support/wait_for_events.rb index e89ee50cf..fb20fc682 100644 --- a/spec/support/wait_for_events.rb +++ b/spec/support/wait_for_events.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # Theoretically, Capybara is clever enough to wait for asynchronous events to # happen (e.g. AJAX). Sadly, this is not always true. For more, read: # diff --git a/spec/views/explore/index.html.slim_spec.rb b/spec/views/explore/index.html.slim_spec.rb index bfb69e7d1..aaf5d4341 100644 --- a/spec/views/explore/index.html.slim_spec.rb +++ b/spec/views/explore/index.html.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "explore/index", type: :view do diff --git a/spec/views/help/index.html.slim_spec.rb b/spec/views/help/index.html.slim_spec.rb index b54e568e3..8c4a693ee 100644 --- a/spec/views/help/index.html.slim_spec.rb +++ b/spec/views/help/index.html.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "help/index" do diff --git a/spec/views/public_activity/webhook/_create.csv.slim_spec.rb b/spec/views/public_activity/webhook/_create.csv.slim_spec.rb index b56865ba8..ccd5678a6 100644 --- a/spec/views/public_activity/webhook/_create.csv.slim_spec.rb +++ b/spec/views/public_activity/webhook/_create.csv.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "public_activity/webhook/_create.csv.slim" do @@ -6,7 +8,7 @@ let!(:registry) { create(:registry) } let!(:user) { create(:admin) } - before :each do + before do user.create_personal_namespace! @webhook = create(:webhook, namespace: user.namespace) @activity = @webhook.create_activity :enabled, owner: user diff --git a/spec/views/public_activity/webhook/_create.html.slim_spec.rb b/spec/views/public_activity/webhook/_create.html.slim_spec.rb index bc90cc325..62806d1bc 100644 --- a/spec/views/public_activity/webhook/_create.html.slim_spec.rb +++ b/spec/views/public_activity/webhook/_create.html.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "public_activity/webhook/_create" do @@ -6,7 +8,7 @@ let!(:registry) { create(:registry) } let!(:user) { create(:admin) } - before :each do + before do user.create_personal_namespace! @webhook = create(:webhook, namespace: user.namespace) @activity = @webhook.create_activity :created, owner: user diff --git a/spec/views/public_activity/webhook/_enabled.csv.slim_spec.rb b/spec/views/public_activity/webhook/_enabled.csv.slim_spec.rb index 5394c48af..4421b8cc1 100644 --- a/spec/views/public_activity/webhook/_enabled.csv.slim_spec.rb +++ b/spec/views/public_activity/webhook/_enabled.csv.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "public_activity/webhook/_enabled.csv.slim" do @@ -6,7 +8,7 @@ let!(:registry) { create(:registry) } let!(:user) { create(:admin) } - before :each do + before do user.create_personal_namespace! @webhook = create(:webhook, namespace: user.namespace) @activity = @webhook.create_activity :enabled, owner: user diff --git a/spec/views/public_activity/webhook/_enabled.html.slim_spec.rb b/spec/views/public_activity/webhook/_enabled.html.slim_spec.rb index 9ecda2c5e..9c68d93f7 100644 --- a/spec/views/public_activity/webhook/_enabled.html.slim_spec.rb +++ b/spec/views/public_activity/webhook/_enabled.html.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "public_activity/webhook/_enabled" do @@ -6,7 +8,7 @@ let!(:registry) { create(:registry) } let!(:user) { create(:admin) } - before :each do + before do user.create_personal_namespace! @webhook = create(:webhook, namespace: user.namespace) @activity = @webhook.create_activity :enabled, owner: user diff --git a/spec/views/search/index.html.slim_spec.rb b/spec/views/search/index.html.slim_spec.rb index 0b92cd91b..dc33b4c4b 100644 --- a/spec/views/search/index.html.slim_spec.rb +++ b/spec/views/search/index.html.slim_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails_helper" describe "search/index" do