Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
4eea104c69
commit
175b4fa261
|
|
@ -315,8 +315,7 @@ export default {
|
|||
|
||||
<gl-dropdown-item
|
||||
v-if="showDelete"
|
||||
class="text-danger"
|
||||
data-qa-selector="delete_board_button"
|
||||
class="text-danger js-delete-board"
|
||||
@click.prevent="showPage('delete')"
|
||||
>
|
||||
{{ s__('IssueBoards|Delete board') }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
class KeysFinder
|
||||
InvalidFingerprint = Class.new(StandardError)
|
||||
GitLabAccessDeniedError = Class.new(StandardError)
|
||||
|
||||
FINGERPRINT_ATTRIBUTES = {
|
||||
'sha256' => 'fingerprint_sha256',
|
||||
'md5' => 'fingerprint'
|
||||
}.freeze
|
||||
|
||||
def initialize(current_user, params)
|
||||
@current_user = current_user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def execute
|
||||
raise GitLabAccessDeniedError unless current_user.admin?
|
||||
raise InvalidFingerprint unless valid_fingerprint_param?
|
||||
|
||||
Key.where(fingerprint_query).first # rubocop: disable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :current_user, :params
|
||||
|
||||
def valid_fingerprint_param?
|
||||
if fingerprint_type == "sha256"
|
||||
Base64.decode64(fingerprint).length == 32
|
||||
else
|
||||
fingerprint =~ /^(\h{2}:){15}\h{2}/
|
||||
end
|
||||
end
|
||||
|
||||
def fingerprint_query
|
||||
fingerprint_attribute = FINGERPRINT_ATTRIBUTES[fingerprint_type]
|
||||
|
||||
Key.arel_table[fingerprint_attribute].eq(fingerprint)
|
||||
end
|
||||
|
||||
def fingerprint_type
|
||||
if params[:fingerprint].start_with?(/sha256:|SHA256:/)
|
||||
"sha256"
|
||||
else
|
||||
"md5"
|
||||
end
|
||||
end
|
||||
|
||||
def fingerprint
|
||||
if fingerprint_type == "sha256"
|
||||
params[:fingerprint].gsub(/sha256:|SHA256:/, "")
|
||||
else
|
||||
params[:fingerprint]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Sha256Attribute
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def sha256_attribute(name)
|
||||
return if ENV['STATIC_VERIFICATION']
|
||||
|
||||
validate_binary_column_exists!(name) unless Rails.env.production?
|
||||
|
||||
attribute(name, Gitlab::Database::Sha256Attribute.new)
|
||||
end
|
||||
|
||||
# This only gets executed in non-production environments as an additional check to ensure
|
||||
# the column is the correct type. In production it should behave like any other attribute.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/merge_requests/5502 for more discussion
|
||||
def validate_binary_column_exists!(name)
|
||||
return unless database_exists?
|
||||
|
||||
unless table_exists?
|
||||
warn "WARNING: sha256_attribute #{name.inspect} is invalid since the table doesn't exist - you may need to run database migrations"
|
||||
return
|
||||
end
|
||||
|
||||
column = columns.find { |c| c.name == name.to_s }
|
||||
|
||||
unless column
|
||||
warn "WARNING: sha256_attribute #{name.inspect} is invalid since the column doesn't exist - you may need to run database migrations"
|
||||
return
|
||||
end
|
||||
|
||||
unless column.type == :binary
|
||||
raise ArgumentError.new("sha256_attribute #{name.inspect} is invalid since the column type is not :binary")
|
||||
end
|
||||
rescue => error
|
||||
Gitlab::AppLogger.error "Sha256Attribute initialization: #{error.message}"
|
||||
raise
|
||||
end
|
||||
|
||||
def database_exists?
|
||||
ApplicationRecord.connection
|
||||
|
||||
true
|
||||
rescue
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,6 +5,9 @@ require 'digest/md5'
|
|||
class Key < ApplicationRecord
|
||||
include AfterCommitQueue
|
||||
include Sortable
|
||||
include Sha256Attribute
|
||||
|
||||
sha256_attribute :fingerprint_sha256
|
||||
|
||||
belongs_to :user
|
||||
|
||||
|
|
@ -34,6 +37,8 @@ class Key < ApplicationRecord
|
|||
after_destroy :post_destroy_hook
|
||||
after_destroy :refresh_user_cache
|
||||
|
||||
alias_attribute :fingerprint_md5, :fingerprint
|
||||
|
||||
def self.regular_keys
|
||||
where(type: ['Key', nil])
|
||||
end
|
||||
|
|
@ -114,10 +119,12 @@ class Key < ApplicationRecord
|
|||
|
||||
def generate_fingerprint
|
||||
self.fingerprint = nil
|
||||
self.fingerprint_sha256 = nil
|
||||
|
||||
return unless public_key.valid?
|
||||
|
||||
self.fingerprint = public_key.fingerprint
|
||||
self.fingerprint_md5 = public_key.fingerprint
|
||||
self.fingerprint_sha256 = public_key.fingerprint("SHA256").gsub("SHA256:", "")
|
||||
end
|
||||
|
||||
def key_meets_restrictions
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ module Git
|
|||
end
|
||||
|
||||
def logger
|
||||
if Sidekiq.server?
|
||||
if Gitlab::Runtime.sidekiq?
|
||||
Sidekiq.logger
|
||||
else
|
||||
# This service runs in Sidekiq, so this shouldn't ever be
|
||||
|
|
|
|||
|
|
@ -17,11 +17,21 @@
|
|||
|
||||
.col-md-8
|
||||
= form_errors(@key, type: 'key') unless @key.valid?
|
||||
%p
|
||||
%span.light= _('Fingerprint:')
|
||||
%code.key-fingerprint= @key.fingerprint
|
||||
%pre.well-pre
|
||||
= @key.key
|
||||
.card
|
||||
.card-header
|
||||
= _('Fingerprints')
|
||||
%ul.content-list
|
||||
%li
|
||||
%span.light= 'MD5:'
|
||||
%code.key-fingerprint= @key.fingerprint
|
||||
- if @key.fingerprint_sha256.present?
|
||||
%li
|
||||
%span.light= 'SHA256:'
|
||||
%code.key-fingerprint= @key.fingerprint_sha256
|
||||
|
||||
|
||||
.col-md-12
|
||||
.float-right
|
||||
- if @key.can_delete?
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: add sha256 fingerprint to keys model, view and extend users API to search user via fingerprint
|
||||
merge_request: 19860
|
||||
author: Roger Meier
|
||||
type: added
|
||||
|
|
@ -22,6 +22,7 @@ module Gitlab
|
|||
require_dependency Rails.root.join('lib/gitlab/current_settings')
|
||||
require_dependency Rails.root.join('lib/gitlab/middleware/read_only')
|
||||
require_dependency Rails.root.join('lib/gitlab/middleware/basic_health_check')
|
||||
require_dependency Rails.root.join('lib/gitlab/runtime')
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration should go into files in config/initializers
|
||||
|
|
@ -255,7 +256,7 @@ module Gitlab
|
|||
caching_config_hash[:compress] = false
|
||||
caching_config_hash[:namespace] = Gitlab::Redis::Cache::CACHE_NAMESPACE
|
||||
caching_config_hash[:expires_in] = 2.weeks # Cache should not grow forever
|
||||
if Sidekiq.server? || defined?(::Puma) # threaded context
|
||||
if Gitlab::Runtime.multi_threaded?
|
||||
caching_config_hash[:pool_size] = Gitlab::Redis::Cache.pool_size
|
||||
caching_config_hash[:pool_timeout] = 1
|
||||
end
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Rails.application.configure do
|
|||
# Do not log asset requests
|
||||
config.assets.quiet = true
|
||||
|
||||
config.allow_concurrency = defined?(::Puma)
|
||||
config.allow_concurrency = Gitlab::Runtime.multi_threaded?
|
||||
|
||||
# BetterErrors live shell (REPL) on every stack frame
|
||||
BetterErrors::Middleware.allow_ip!("127.0.0.1/0")
|
||||
|
|
|
|||
|
|
@ -75,5 +75,5 @@ Rails.application.configure do
|
|||
|
||||
config.eager_load = true
|
||||
|
||||
config.allow_concurrency = defined?(::Puma)
|
||||
config.allow_concurrency = Gitlab::Runtime.multi_threaded?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
begin
|
||||
Gitlab::AppLogger.info("Runtime: #{Gitlab::Runtime.name}")
|
||||
rescue => e
|
||||
message = <<-NOTICE
|
||||
\n!! RUNTIME IDENTIFICATION FAILED: #{e}
|
||||
Runtime based configuration settings may not work properly.
|
||||
If you continue to see this error, please file an issue via
|
||||
https://gitlab.com/gitlab-org/gitlab/issues/new
|
||||
NOTICE
|
||||
Gitlab::AppLogger.error(message)
|
||||
end
|
||||
|
|
@ -364,7 +364,7 @@ Gitlab.ee do
|
|||
# To ensure acceptable performance we only allow feature to be used with
|
||||
# multithreaded web-server Puma. This will be removed once download logic is moved
|
||||
# to GitLab workhorse
|
||||
Settings.dependency_proxy['enabled'] = false unless defined?(::Puma)
|
||||
Settings.dependency_proxy['enabled'] = false unless Gitlab::Runtime.puma?
|
||||
end
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ require 'prometheus/client'
|
|||
def prometheus_default_multiproc_dir
|
||||
return unless Rails.env.development? || Rails.env.test?
|
||||
|
||||
if Sidekiq.server?
|
||||
if Gitlab::Runtime.sidekiq?
|
||||
Rails.root.join('tmp/prometheus_multiproc_dir/sidekiq')
|
||||
elsif defined?(Unicorn::Worker)
|
||||
elsif Gitlab::Runtime.unicorn?
|
||||
Rails.root.join('tmp/prometheus_multiproc_dir/unicorn')
|
||||
elsif defined?(::Puma)
|
||||
elsif Gitlab::Runtime.puma?
|
||||
Rails.root.join('tmp/prometheus_multiproc_dir/puma')
|
||||
else
|
||||
Rails.root.join('tmp/prometheus_multiproc_dir')
|
||||
|
|
@ -55,9 +55,9 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
|
|||
Gitlab::Cluster::LifecycleEvents.on_master_start do
|
||||
::Prometheus::Client.reinitialize_on_pid_change(force: true)
|
||||
|
||||
if defined?(::Unicorn)
|
||||
if Gitlab::Runtime.unicorn?
|
||||
Gitlab::Metrics::Samplers::UnicornSampler.instance(Settings.monitoring.unicorn_sampler_interval).start
|
||||
elsif defined?(::Puma)
|
||||
elsif Gitlab::Runtime.puma?
|
||||
Gitlab::Metrics::Samplers::PumaSampler.instance(Settings.monitoring.puma_sampler_interval).start
|
||||
end
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
|
|||
end
|
||||
end
|
||||
|
||||
if defined?(::Unicorn) || defined?(::Puma)
|
||||
if Gitlab::Runtime.app_server?
|
||||
Gitlab::Cluster::LifecycleEvents.on_master_start do
|
||||
Gitlab::Metrics::Exporter::WebExporter.instance.start
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Don't handle sidekiq configuration as it
|
||||
# has its own special active record configuration here
|
||||
if defined?(ActiveRecord::Base) && !Sidekiq.server?
|
||||
if defined?(ActiveRecord::Base) && !Gitlab::Runtime.sidekiq?
|
||||
Gitlab::Cluster::LifecycleEvents.on_worker_start do
|
||||
ActiveSupport.on_load(:active_record) do
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
|
|
|||
|
|
@ -5,10 +5,8 @@
|
|||
#
|
||||
# Follow-up the issue: https://gitlab.com/gitlab-org/gitlab/issues/34107
|
||||
|
||||
if defined?(::Puma)
|
||||
if Gitlab::Runtime.puma?
|
||||
Puma::Cluster.prepend(::Gitlab::Cluster::Mixins::PumaCluster)
|
||||
end
|
||||
|
||||
if defined?(::Unicorn::HttpServer)
|
||||
elsif Gitlab::Runtime.unicorn?
|
||||
Unicorn::HttpServer.prepend(::Gitlab::Cluster::Mixins::UnicornHttpServer)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# when running on puma, scale connection pool size with the number
|
||||
# of threads per worker process
|
||||
if defined?(::Puma)
|
||||
if Gitlab::Runtime.puma?
|
||||
db_config = Gitlab::Database.config ||
|
||||
Rails.application.config.database_configuration[Rails.env]
|
||||
puma_options = Puma.cli_config.options
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Only use Lograge for Rails
|
||||
unless Sidekiq.server?
|
||||
unless Gitlab::Runtime.sidekiq?
|
||||
filename = File.join(Rails.root, 'log', "#{Rails.env}_json.log")
|
||||
|
||||
Rails.application.configure do
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
# and it's used only as the last resort. In such case this termination is
|
||||
# logged and we should fix the potential timeout issue in the code itself.
|
||||
|
||||
if defined?(::Puma) && !Rails.env.test?
|
||||
if Gitlab::Runtime.puma? && !Rails.env.test?
|
||||
require 'rack/timeout/base'
|
||||
|
||||
Gitlab::Application.configure do |config|
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ if Labkit::Tracing.enabled?
|
|||
end
|
||||
|
||||
# Instrument Sidekiq server calls when running Sidekiq server
|
||||
if Sidekiq.server?
|
||||
if Gitlab::Runtime.sidekiq?
|
||||
Sidekiq.configure_server do |config|
|
||||
config.server_middleware do |chain|
|
||||
chain.add Labkit::Tracing::Sidekiq::ServerMiddleware
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
if defined?(::Puma) && ::Puma.cli_config.options[:workers].to_i.zero?
|
||||
if Gitlab::Runtime.puma? && ::Puma.cli_config.options[:workers].to_i.zero?
|
||||
raise 'Puma is only supported in Cluster-mode: workers > 0'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddFingerprintSha256ToKey < ActiveRecord::Migration[5.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
add_column(:keys, :fingerprint_sha256, :binary)
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column(:keys, :fingerprint_sha256) if column_exists?(:keys, :fingerprint_sha256)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddFingerprintSha256IndexToKey < ActiveRecord::Migration[5.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_concurrent_index(:keys, "fingerprint_sha256")
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index(:keys, "fingerprint_sha256")
|
||||
end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2019_12_06_122926) do
|
||||
ActiveRecord::Schema.define(version: 2019_12_08_071112) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_trgm"
|
||||
|
|
@ -2206,7 +2206,9 @@ ActiveRecord::Schema.define(version: 2019_12_06_122926) do
|
|||
t.string "fingerprint"
|
||||
t.boolean "public", default: false, null: false
|
||||
t.datetime "last_used_at"
|
||||
t.binary "fingerprint_sha256"
|
||||
t.index ["fingerprint"], name: "index_keys_on_fingerprint", unique: true
|
||||
t.index ["fingerprint_sha256"], name: "index_keys_on_fingerprint_sha256"
|
||||
t.index ["id", "type"], name: "index_on_deploy_keys_id_and_type_and_public", unique: true, where: "(public = true)"
|
||||
t.index ["user_id"], name: "index_keys_on_user_id"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,13 +4,19 @@
|
|||
|
||||
Get SSH key with user by ID of an SSH key. Note only administrators can lookup SSH key with user by ID of an SSH key.
|
||||
|
||||
```
|
||||
```text
|
||||
GET /keys/:id
|
||||
```
|
||||
|
||||
Parameters:
|
||||
| Attribute | Type | Required | Description |
|
||||
|:----------|:--------|:---------|:---------------------|
|
||||
| `id` | integer | yes | The ID of an SSH key |
|
||||
|
||||
- `id` (required) - The ID of an SSH key
|
||||
Example request:
|
||||
|
||||
```sh
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/keys/1
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -51,3 +57,74 @@ Parameters:
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Get user by fingerprint of SSH key
|
||||
|
||||
You can search for a user that owns a specific SSH key. Note only administrators can lookup SSH key with the fingerprint of an SSH key.
|
||||
|
||||
```text
|
||||
GET /keys
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|:--------------|:-------|:---------|:------------------------------|
|
||||
| `fingerprint` | string | yes | The fingerprint of an SSH key |
|
||||
|
||||
Example request:
|
||||
|
||||
```sh
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/keys?fingerprint=ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1'
|
||||
```
|
||||
|
||||
If using sha256 fingerprint API calls, make sure that the fingerprint is URL-encoded.
|
||||
|
||||
For example, `/` is represented by `%2F` and `:` is represented by`%3A`:
|
||||
|
||||
```sh
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/keys?fingerprint=SHA256%3AnUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo%2FlCg
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Sample key 1",
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1016k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
|
||||
"created_at": "2019-11-14T15:11:13.222Z",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"name": "Administrator",
|
||||
"username": "root",
|
||||
"state": "active",
|
||||
"avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
|
||||
"web_url": "http://0.0.0.0:3000/root",
|
||||
"created_at": "2019-11-14T15:09:34.831Z",
|
||||
"bio": null,
|
||||
"location": null,
|
||||
"public_email": "",
|
||||
"skype": "",
|
||||
"linkedin": "",
|
||||
"twitter": "",
|
||||
"website_url": "",
|
||||
"organization": null,
|
||||
"last_sign_in_at": "2019-11-16T22:41:26.663Z",
|
||||
"confirmed_at": "2019-11-14T15:09:34.575Z",
|
||||
"last_activity_on": "2019-11-20",
|
||||
"email": "admin@example.com",
|
||||
"theme_id": 1,
|
||||
"color_scheme_id": 1,
|
||||
"projects_limit": 100000,
|
||||
"current_sign_in_at": "2019-11-19T14:42:18.078Z",
|
||||
"identities": [
|
||||
],
|
||||
"can_create_group": true,
|
||||
"can_create_project": true,
|
||||
"two_factor_enabled": false,
|
||||
"external": false,
|
||||
"private_profile": false,
|
||||
"shared_runners_minutes_limit": null,
|
||||
"extra_shared_runners_minutes_limit": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -16,6 +16,23 @@ module API
|
|||
|
||||
present key, with: Entities::SSHKeyWithUser, current_user: current_user
|
||||
end
|
||||
|
||||
desc 'Get SSH Key information' do
|
||||
success Entities::UserWithAdmin
|
||||
end
|
||||
params do
|
||||
requires :fingerprint, type: String, desc: 'Search for a SSH fingerprint'
|
||||
end
|
||||
get do
|
||||
authenticated_with_full_private_access!
|
||||
|
||||
key = KeysFinder.new(current_user, params).execute
|
||||
|
||||
not_found!('Key') unless key
|
||||
present key, with: Entities::SSHKeyWithUser, current_user: current_user
|
||||
rescue KeysFinder::InvalidFingerprint
|
||||
render_api_error!('Failed to return the key', 400)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ module Gitlab
|
|||
end
|
||||
|
||||
def self.process_name
|
||||
return 'sidekiq' if Sidekiq.server?
|
||||
return 'console' if defined?(Rails::Console)
|
||||
return 'sidekiq' if Gitlab::Runtime.sidekiq?
|
||||
return 'console' if Gitlab::Runtime.console?
|
||||
return 'test' if Rails.env.test?
|
||||
|
||||
'web'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,16 @@
|
|||
# Full project: https://gitlab.com/pages/hugo
|
||||
image: dettmering/hugo-build
|
||||
---
|
||||
# All available Hugo versions are listed here:
|
||||
# https://gitlab.com/pages/hugo/container_registry
|
||||
image: registry.gitlab.com/pages/hugo:latest
|
||||
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
test:
|
||||
script:
|
||||
- hugo
|
||||
except:
|
||||
- master
|
||||
|
||||
pages:
|
||||
script:
|
||||
|
|
@ -9,9 +20,3 @@ pages:
|
|||
- public
|
||||
only:
|
||||
- master
|
||||
|
||||
test:
|
||||
script:
|
||||
- hugo
|
||||
except:
|
||||
- master
|
||||
|
|
|
|||
|
|
@ -149,10 +149,10 @@ module Gitlab
|
|||
|
||||
def in_clustered_environment?
|
||||
# Sidekiq doesn't fork
|
||||
return false if Sidekiq.server?
|
||||
return false if Gitlab::Runtime.sidekiq?
|
||||
|
||||
# Unicorn always forks
|
||||
return true if defined?(::Unicorn)
|
||||
return true if Gitlab::Runtime.unicorn?
|
||||
|
||||
# Puma sometimes forks
|
||||
return true if in_clustered_puma?
|
||||
|
|
@ -162,7 +162,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def in_clustered_puma?
|
||||
return false unless defined?(::Puma)
|
||||
return false unless Gitlab::Runtime.puma?
|
||||
|
||||
@puma_options && @puma_options[:workers] && @puma_options[:workers] > 0
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Database
|
||||
# Class for casting binary data to hexadecimal SHA256 hashes (and vice-versa).
|
||||
#
|
||||
# Using Sha256Attribute allows you to store SHA256 values as binary while still
|
||||
# using them as if they were stored as string values. This gives you the
|
||||
# ease of use of string values, but without the storage overhead.
|
||||
class Sha256Attribute < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Bytea
|
||||
# Casts binary data to a SHA256 and remove trailing = and newline from encode64
|
||||
def deserialize(value)
|
||||
value = super(value)
|
||||
if value.present?
|
||||
Base64.encode64(value).delete("=").chomp("\n")
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
# Casts a SHA256 in a proper binary format. which is 32 bytes long
|
||||
def serialize(value)
|
||||
arg = if value.present?
|
||||
Base64.decode64(value)
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
super(arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -29,7 +29,7 @@ module Gitlab
|
|||
PEM_REGEX = /\-+BEGIN CERTIFICATE\-+.+?\-+END CERTIFICATE\-+/m.freeze
|
||||
SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'
|
||||
MAXIMUM_GITALY_CALLS = 30
|
||||
CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
|
||||
CLIENT_NAME = (Gitlab::Runtime.sidekiq? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
|
||||
GITALY_METADATA_FILENAME = '.gitaly-metadata'
|
||||
|
||||
MUTEX = Mutex.new
|
||||
|
|
@ -383,17 +383,13 @@ module Gitlab
|
|||
end
|
||||
|
||||
def self.long_timeout
|
||||
if web_app_server?
|
||||
if Gitlab::Runtime.app_server?
|
||||
default_timeout
|
||||
else
|
||||
6.hours
|
||||
end
|
||||
end
|
||||
|
||||
def self.web_app_server?
|
||||
defined?(::Unicorn) || defined?(::Puma)
|
||||
end
|
||||
|
||||
def self.storage_metadata_file_path(storage)
|
||||
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
|
||||
File.join(
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def cleanup_time
|
||||
Sidekiq.server? ? BG_CLEANUP_RUNTIME_S : FG_CLEANUP_RUNTIME_S
|
||||
Gitlab::Runtime.sidekiq? ? BG_CLEANUP_RUNTIME_S : FG_CLEANUP_RUNTIME_S
|
||||
end
|
||||
|
||||
def tmp_keychains_created
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def check
|
||||
return unless defined?(::Puma)
|
||||
return unless Gitlab::Runtime.puma?
|
||||
|
||||
stats = Puma.stats
|
||||
stats = JSON.parse(stats)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ module Gitlab
|
|||
# to change so we can cache the list of servers.
|
||||
def http_servers
|
||||
strong_memoize(:http_servers) do
|
||||
next unless defined?(::Unicorn::HttpServer)
|
||||
next unless Gitlab::Runtime.unicorn?
|
||||
|
||||
ObjectSpace.each_object(::Unicorn::HttpServer).to_a
|
||||
end
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def timeout_time
|
||||
Sidekiq.server? ? TIMEOUT_BACKGROUND : TIMEOUT_FOREGROUND
|
||||
Gitlab::Runtime.sidekiq? ? TIMEOUT_BACKGROUND : TIMEOUT_FOREGROUND
|
||||
end
|
||||
|
||||
def link_dependencies(text, highlighted_text)
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ module Gitlab
|
|||
#
|
||||
class InsecureKeyFingerprint
|
||||
attr_accessor :key
|
||||
alias_attribute :fingerprint_md5, :fingerprint
|
||||
|
||||
#
|
||||
# Gets the base64 encoded string representing a rsa or dsa key
|
||||
|
|
@ -21,5 +22,9 @@ module Gitlab
|
|||
def fingerprint
|
||||
OpenSSL::Digest::MD5.hexdigest(Base64.decode64(@key)).scan(/../).join(':')
|
||||
end
|
||||
|
||||
def fingerprint_sha256
|
||||
Digest::SHA256.base64digest(Base64.decode64(@key)).scan(/../).join('').delete("=")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ module Gitlab
|
|||
|
||||
# Returns the prefix to use for the name of a series.
|
||||
def series_prefix
|
||||
@series_prefix ||= Sidekiq.server? ? 'sidekiq_' : 'rails_'
|
||||
@series_prefix ||= Gitlab::Runtime.sidekiq? ? 'sidekiq_' : 'rails_'
|
||||
end
|
||||
|
||||
# Allow access from other metrics related middlewares
|
||||
|
|
|
|||
|
|
@ -39,14 +39,10 @@ module Gitlab
|
|||
end
|
||||
|
||||
def add_metric(series, values, tags = {})
|
||||
prefix = sidekiq? ? 'sidekiq_' : 'rails_'
|
||||
prefix = Gitlab::Runtime.sidekiq? ? 'sidekiq_' : 'rails_'
|
||||
|
||||
@metrics << Metric.new("#{prefix}#{series}", values, tags)
|
||||
end
|
||||
|
||||
def sidekiq?
|
||||
Sidekiq.server?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ module Gitlab
|
|||
# it takes around 80ms. The instances of HttpServers are not a subject
|
||||
# to change so we can cache the list of servers.
|
||||
def http_servers
|
||||
return [] unless defined?(::Unicorn::HttpServer)
|
||||
return [] unless Gitlab::Runtime.unicorn?
|
||||
|
||||
@http_servers ||= ObjectSpace.each_object(::Unicorn::HttpServer).to_a
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ module Gitlab
|
|||
def pool_size
|
||||
# heuristic constant 5 should be a config setting somewhere -- related to CPU count?
|
||||
size = 5
|
||||
if Sidekiq.server?
|
||||
if Gitlab::Runtime.sidekiq?
|
||||
# the pool will be used in a multi-threaded context
|
||||
size += Sidekiq.options[:concurrency]
|
||||
elsif defined?(::Puma)
|
||||
elsif Gitlab::Runtime.puma?
|
||||
size += Puma.cli_config.options[:max_threads]
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
# Provides routines to identify the current runtime as which the application
|
||||
# executes, such as whether it is an application server and which one.
|
||||
module Runtime
|
||||
class << self
|
||||
def name
|
||||
matches = []
|
||||
matches << :puma if puma?
|
||||
matches << :unicorn if unicorn?
|
||||
matches << :console if console?
|
||||
matches << :sidekiq if sidekiq?
|
||||
|
||||
raise "Ambiguous process match: #{matches}" if matches.size > 1
|
||||
|
||||
matches.first || :unknown
|
||||
end
|
||||
|
||||
def puma?
|
||||
!!(defined?(::Puma) && bin == 'puma')
|
||||
end
|
||||
|
||||
# For unicorn, we need to check for actual server instances to avoid false positives.
|
||||
def unicorn?
|
||||
!!(defined?(::Unicorn) && defined?(::Unicorn::HttpServer))
|
||||
end
|
||||
|
||||
def sidekiq?
|
||||
!!(defined?(::Sidekiq) && Sidekiq.server? && bin == 'sidekiq')
|
||||
end
|
||||
|
||||
def console?
|
||||
!!defined?(::Rails::Console)
|
||||
end
|
||||
|
||||
def app_server?
|
||||
puma? || unicorn?
|
||||
end
|
||||
|
||||
def multi_threaded?
|
||||
puma? || sidekiq?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Some example values from my system:
|
||||
# puma: /data/cache/bundle-2.5/bin/puma
|
||||
# unicorn: unicorn_rails master -E development -c /tmp/unicorn.rb -l 0.0.0.0:8080
|
||||
# sidekiq: /data/cache/bundle-2.5/bin/sidekiq
|
||||
# thin: bin/rails
|
||||
# console: bin/rails
|
||||
def script_name
|
||||
$0
|
||||
end
|
||||
|
||||
def bin
|
||||
File.basename(script_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,11 +5,11 @@ module Prometheus
|
|||
extend self
|
||||
|
||||
def worker_id
|
||||
if Sidekiq.server?
|
||||
if Gitlab::Runtime.sidekiq?
|
||||
sidekiq_worker_id
|
||||
elsif defined?(Unicorn::Worker)
|
||||
elsif Gitlab::Runtime.unicorn?
|
||||
unicorn_worker_id
|
||||
elsif defined?(::Puma)
|
||||
elsif Gitlab::Runtime.puma?
|
||||
puma_worker_id
|
||||
else
|
||||
unknown_process_id
|
||||
|
|
|
|||
|
|
@ -7703,9 +7703,6 @@ msgstr ""
|
|||
msgid "Fingerprint"
|
||||
msgstr ""
|
||||
|
||||
msgid "Fingerprint:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Fingerprints"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe KeysFinder do
|
||||
subject(:keys_finder) { described_class.new(user, params) }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:fingerprint_type) { 'md5' }
|
||||
let(:fingerprint) { 'ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1' }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
type: fingerprint_type,
|
||||
fingerprint: fingerprint
|
||||
}
|
||||
end
|
||||
|
||||
let!(:key) do
|
||||
create(:key, user: user,
|
||||
key: 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1016k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=',
|
||||
fingerprint: 'ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1',
|
||||
fingerprint_sha256: 'nUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo/lCg'
|
||||
)
|
||||
end
|
||||
|
||||
context 'with a regular user' do
|
||||
it 'raises GitLabAccessDeniedError' do
|
||||
expect do
|
||||
keys_finder.execute
|
||||
end.to raise_error(KeysFinder::GitLabAccessDeniedError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an admin user' do
|
||||
let(:user) {create(:admin)}
|
||||
|
||||
context 'with invalid MD5 fingerprint' do
|
||||
let(:fingerprint) { '11:11:11:11' }
|
||||
|
||||
it 'raises InvalidFingerprint' do
|
||||
expect { keys_finder.execute }
|
||||
.to raise_error(KeysFinder::InvalidFingerprint)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid SHA fingerprint' do
|
||||
let(:fingerprint_type) { 'sha256' }
|
||||
let(:fingerprint) { 'nUhzNyftwAAKs7HufskYTte2g' }
|
||||
|
||||
it 'raises InvalidFingerprint' do
|
||||
expect { keys_finder.execute }
|
||||
.to raise_error(KeysFinder::InvalidFingerprint)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid MD5 params' do
|
||||
it 'returns key if the fingerprint is found' do
|
||||
result = keys_finder.execute
|
||||
|
||||
expect(result).to eq(key)
|
||||
expect(key.user).to eq(user)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid SHA256 params' do
|
||||
let(:fingerprint) { 'ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1' }
|
||||
|
||||
it 'returns key if the fingerprint is found' do
|
||||
result = keys_finder.execute
|
||||
|
||||
expect(result).to eq(key)
|
||||
expect(key.user).to eq(user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -16,6 +16,7 @@ describe 'Database config initializer' do
|
|||
let(:puma_options) { { max_threads: 8 } }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
|
||||
stub_const("Puma", puma)
|
||||
allow(puma).to receive_message_chain(:cli_config, :options).and_return(puma_options)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ describe Gitlab::GitalyClient do
|
|||
|
||||
context 'running in Unicorn' do
|
||||
before do
|
||||
stub_const('Unicorn', 1)
|
||||
allow(Gitlab::Runtime).to receive(:unicorn?).and_return(true)
|
||||
end
|
||||
|
||||
it { expect(subject.long_timeout).to eq(55) }
|
||||
|
|
@ -34,7 +34,7 @@ describe Gitlab::GitalyClient do
|
|||
|
||||
context 'running in Puma' do
|
||||
before do
|
||||
stub_const('Puma', 1)
|
||||
allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
|
||||
end
|
||||
|
||||
it { expect(subject.long_timeout).to eq(55) }
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ describe Gitlab::Gpg do
|
|||
|
||||
context 'when running in Sidekiq' do
|
||||
before do
|
||||
allow(Sidekiq).to receive(:server?).and_return(true)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
|
||||
end
|
||||
|
||||
it_behaves_like 'multiple deletion attempts of the tmp-dir', described_class::BG_CLEANUP_RUNTIME_S
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ describe Gitlab::HealthChecks::PumaCheck do
|
|||
|
||||
context 'when Puma is not loaded' do
|
||||
before do
|
||||
allow(Gitlab::Runtime).to receive(:puma?).and_return(false)
|
||||
hide_const('Puma')
|
||||
end
|
||||
|
||||
|
|
@ -33,6 +34,7 @@ describe Gitlab::HealthChecks::PumaCheck do
|
|||
|
||||
context 'when Puma is loaded' do
|
||||
before do
|
||||
allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
|
||||
stub_const('Puma', Module.new)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ describe Gitlab::HealthChecks::UnicornCheck do
|
|||
|
||||
context 'when Unicorn is not loaded' do
|
||||
before do
|
||||
allow(Gitlab::Runtime).to receive(:unicorn?).and_return(false)
|
||||
hide_const('Unicorn')
|
||||
end
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ describe Gitlab::HealthChecks::UnicornCheck do
|
|||
let(:http_server_class) { Struct.new(:worker_processes) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Runtime).to receive(:unicorn?).and_return(true)
|
||||
stub_const('Unicorn::HttpServer', http_server_class)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ describe Gitlab::Highlight do
|
|||
end
|
||||
|
||||
it 'utilizes longer timeout for sidekiq' do
|
||||
allow(Sidekiq).to receive(:server?).and_return(true)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
|
||||
expect(Timeout).to receive(:timeout).with(described_class::TIMEOUT_BACKGROUND).and_call_original
|
||||
|
||||
subject.highlight("Content")
|
||||
|
|
|
|||
|
|
@ -11,10 +11,17 @@ describe Gitlab::InsecureKeyFingerprint do
|
|||
end
|
||||
|
||||
let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" }
|
||||
let(:fingerprint_sha256) { "MQHWhS9nhzUezUdD42ytxubZoBKrZLbyBZzxCkmnxXc" }
|
||||
|
||||
describe "#fingerprint" do
|
||||
it "generates the key's fingerprint" do
|
||||
expect(described_class.new(key.split[1]).fingerprint).to eq(fingerprint)
|
||||
expect(described_class.new(key.split[1]).fingerprint_md5).to eq(fingerprint)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#fingerprint" do
|
||||
it "generates the key's fingerprint" do
|
||||
expect(described_class.new(key.split[1]).fingerprint_sha256).to eq(fingerprint_sha256)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ describe Gitlab::Metrics::Samplers::InfluxSampler do
|
|||
|
||||
describe '#add_metric' do
|
||||
it 'prefixes the series name for a Rails process' do
|
||||
expect(sampler).to receive(:sidekiq?).and_return(false)
|
||||
expect(Gitlab::Runtime).to receive(:sidekiq?).and_return(false)
|
||||
|
||||
expect(Gitlab::Metrics::Metric).to receive(:new)
|
||||
.with('rails_cats', { value: 10 }, {})
|
||||
|
|
@ -73,7 +73,7 @@ describe Gitlab::Metrics::Samplers::InfluxSampler do
|
|||
end
|
||||
|
||||
it 'prefixes the series name for a Sidekiq process' do
|
||||
expect(sampler).to receive(:sidekiq?).and_return(true)
|
||||
expect(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
|
||||
|
||||
expect(Gitlab::Metrics::Metric).to receive(:new)
|
||||
.with('sidekiq_cats', { value: 10 }, {})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Runtime do
|
||||
REAL_PATH = $0
|
||||
|
||||
after(:all) do
|
||||
$0 = REAL_PATH
|
||||
end
|
||||
|
||||
context "when unknown" do
|
||||
it "identifies as :unknown" do
|
||||
expect(subject.name).to eq(:unknown)
|
||||
end
|
||||
end
|
||||
|
||||
context "on multiple matches" do
|
||||
before do
|
||||
$0 = '/data/cache/bundle-2.5/bin/puma'
|
||||
stub_const('::Puma', double)
|
||||
stub_const('::Rails::Console', double)
|
||||
end
|
||||
|
||||
it "raises an exception when trying to identify" do
|
||||
expect { subject.name }.to raise_error(RuntimeError, "Ambiguous process match: [:puma, :console]")
|
||||
end
|
||||
end
|
||||
|
||||
context "puma" do
|
||||
let(:puma_type) { double('::Puma') }
|
||||
|
||||
before do
|
||||
$0 = '/data/cache/bundle-2.5/bin/puma'
|
||||
stub_const('::Puma', puma_type)
|
||||
end
|
||||
|
||||
it "identifies itself" do
|
||||
expect(subject.name).to eq(:puma)
|
||||
expect(subject.puma?).to be(true)
|
||||
end
|
||||
|
||||
it "does not identify as others" do
|
||||
expect(subject.unicorn?).to be(false)
|
||||
expect(subject.sidekiq?).to be(false)
|
||||
expect(subject.console?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "unicorn" do
|
||||
let(:unicorn_type) { Module.new }
|
||||
let(:unicorn_server_type) { Class.new }
|
||||
|
||||
before do
|
||||
$0 = 'unicorn_rails master -E development -c /tmp/unicorn.rb -l 0.0.0.0:8080'
|
||||
stub_const('::Unicorn', unicorn_type)
|
||||
stub_const('::Unicorn::HttpServer', unicorn_server_type)
|
||||
end
|
||||
|
||||
it "identifies itself" do
|
||||
expect(subject.name).to eq(:unicorn)
|
||||
expect(subject.unicorn?).to be(true)
|
||||
end
|
||||
|
||||
it "does not identify as others" do
|
||||
expect(subject.puma?).to be(false)
|
||||
expect(subject.sidekiq?).to be(false)
|
||||
expect(subject.console?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "sidekiq" do
|
||||
let(:sidekiq_type) { double('::Sidekiq') }
|
||||
|
||||
before do
|
||||
$0 = '/data/cache/bundle-2.5/bin/sidekiq'
|
||||
stub_const('::Sidekiq', sidekiq_type)
|
||||
allow(sidekiq_type).to receive(:server?).and_return(true)
|
||||
end
|
||||
|
||||
it "identifies itself" do
|
||||
expect(subject.name).to eq(:sidekiq)
|
||||
expect(subject.sidekiq?).to be(true)
|
||||
end
|
||||
|
||||
it "does not identify as others" do
|
||||
expect(subject.unicorn?).to be(false)
|
||||
expect(subject.puma?).to be(false)
|
||||
expect(subject.console?).to be(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "console" do
|
||||
let(:console_type) { double('::Rails::Console') }
|
||||
|
||||
before do
|
||||
$0 = 'bin/rails'
|
||||
stub_const('::Rails::Console', console_type)
|
||||
end
|
||||
|
||||
it "identifies itself" do
|
||||
expect(subject.name).to eq(:console)
|
||||
expect(subject.console?).to be(true)
|
||||
end
|
||||
|
||||
it "does not identify as others" do
|
||||
expect(subject.unicorn?).to be(false)
|
||||
expect(subject.sidekiq?).to be(false)
|
||||
expect(subject.puma?).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -183,6 +183,34 @@ describe Gitlab::SSHPublicKey, lib: true do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#fingerprint in SHA256 format' do
|
||||
subject { public_key.fingerprint("SHA256").gsub("SHA256:", "") if public_key.fingerprint("SHA256") }
|
||||
|
||||
where(:factory, :fingerprint_sha256) do
|
||||
[
|
||||
[:rsa_key_2048, 'GdtgO0eHbwLB+mK47zblkoXujkqKRZjgMQrHH6Kks3E'],
|
||||
[:rsa_key_4096, 'ByDU7hQ1JB95l6p53rHrffc4eXvEtqGUtQhS+Dhyy7g'],
|
||||
[:rsa_key_5120, 'PCCupLbFHScm4AbEufbGDvhBU27IM0MVAor715qKQK8'],
|
||||
[:rsa_key_8192, 'CtHFQAS+9Hb8z4vrv4gVQPsHjNN0WIZhWODaB1mQLs4'],
|
||||
[:dsa_key_2048, '+a3DQ7cU5GM+gaYOfmc0VWNnykHQSuth3VRcCpWuYNI'],
|
||||
[:ecdsa_key_256, 'C+I5k3D+IGeM6k5iBR1ZsphqTKV+7uvL/XZ5hcrTr7g'],
|
||||
[:ed25519_key_256, 'DCKAjzxWrdOTjaGKBBjtCW8qY5++GaiAJflrHPmp6W0']
|
||||
]
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:key) { attributes_for(factory)[:key] }
|
||||
|
||||
it { is_expected.to eq(fingerprint_sha256) }
|
||||
end
|
||||
|
||||
context 'with an invalid SSH key' do
|
||||
let(:key) { 'this is not a key' }
|
||||
|
||||
it { is_expected.to be_nil }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#key_text' do
|
||||
let(:key) { 'this is not a key' }
|
||||
|
||||
|
|
|
|||
|
|
@ -6,16 +6,13 @@ describe Prometheus::PidProvider do
|
|||
describe '.worker_id' do
|
||||
subject { described_class.worker_id }
|
||||
|
||||
let(:sidekiq_module) { Module.new }
|
||||
|
||||
before do
|
||||
allow(sidekiq_module).to receive(:server?).and_return(false)
|
||||
stub_const('Sidekiq', sidekiq_module)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(false)
|
||||
end
|
||||
|
||||
context 'when running in Sidekiq server mode' do
|
||||
before do
|
||||
expect(Sidekiq).to receive(:server?).and_return(true)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
|
||||
end
|
||||
|
||||
context 'in a clustered setup' do
|
||||
|
|
@ -33,8 +30,7 @@ describe Prometheus::PidProvider do
|
|||
|
||||
context 'when running in Unicorn mode' do
|
||||
before do
|
||||
stub_const('Unicorn::Worker', Class.new)
|
||||
hide_const('Puma')
|
||||
allow(Gitlab::Runtime).to receive(:unicorn?).and_return(true)
|
||||
|
||||
expect(described_class).to receive(:process_name)
|
||||
.at_least(:once)
|
||||
|
|
@ -94,8 +90,7 @@ describe Prometheus::PidProvider do
|
|||
|
||||
context 'when running in Puma mode' do
|
||||
before do
|
||||
stub_const('Puma', Module.new)
|
||||
hide_const('Unicorn::Worker')
|
||||
allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
|
||||
|
||||
expect(described_class).to receive(:process_name)
|
||||
.at_least(:once)
|
||||
|
|
@ -116,11 +111,6 @@ describe Prometheus::PidProvider do
|
|||
end
|
||||
|
||||
context 'when running in unknown mode' do
|
||||
before do
|
||||
hide_const('Puma')
|
||||
hide_const('Unicorn::Worker')
|
||||
end
|
||||
|
||||
it { is_expected.to eq "process_#{Process.pid}" }
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Sha256Attribute do
|
||||
let(:model) { Class.new { include Sha256Attribute } }
|
||||
|
||||
before do
|
||||
columns = [
|
||||
double(:column, name: 'name', type: :text),
|
||||
double(:column, name: 'sha256', type: :binary)
|
||||
]
|
||||
|
||||
allow(model).to receive(:columns).and_return(columns)
|
||||
end
|
||||
|
||||
describe '#sha_attribute' do
|
||||
context 'when in non-production' do
|
||||
before do
|
||||
stub_rails_env('development')
|
||||
end
|
||||
|
||||
context 'when the table exists' do
|
||||
before do
|
||||
allow(model).to receive(:table_exists?).and_return(true)
|
||||
end
|
||||
|
||||
it 'defines a SHA attribute for a binary column' do
|
||||
expect(model).to receive(:attribute)
|
||||
.with(:sha256, an_instance_of(Gitlab::Database::Sha256Attribute))
|
||||
|
||||
model.sha256_attribute(:sha256)
|
||||
end
|
||||
|
||||
it 'raises ArgumentError when the column type is not :binary' do
|
||||
expect { model.sha256_attribute(:name) }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the table does not exist' do
|
||||
it 'allows the attribute to be added and issues a warning' do
|
||||
allow(model).to receive(:table_exists?).and_return(false)
|
||||
|
||||
expect(model).not_to receive(:columns)
|
||||
expect(model).to receive(:attribute)
|
||||
expect(model).to receive(:warn)
|
||||
|
||||
model.sha256_attribute(:name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the column does not exist' do
|
||||
it 'allows the attribute to be added and issues a warning' do
|
||||
allow(model).to receive(:table_exists?).and_return(true)
|
||||
|
||||
expect(model).to receive(:columns)
|
||||
expect(model).to receive(:attribute)
|
||||
expect(model).to receive(:warn)
|
||||
|
||||
model.sha256_attribute(:no_name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when other execeptions are raised' do
|
||||
it 'logs and re-rasises the error' do
|
||||
allow(model).to receive(:table_exists?).and_raise(ActiveRecord::NoDatabaseError.new('does not exist'))
|
||||
|
||||
expect(model).not_to receive(:columns)
|
||||
expect(model).not_to receive(:attribute)
|
||||
expect(Gitlab::AppLogger).to receive(:error)
|
||||
|
||||
expect { model.sha256_attribute(:name) }.to raise_error(ActiveRecord::NoDatabaseError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when in production' do
|
||||
before do
|
||||
stub_rails_env('production')
|
||||
end
|
||||
|
||||
it 'defines a SHA attribute' do
|
||||
expect(model).not_to receive(:table_exists?)
|
||||
expect(model).not_to receive(:columns)
|
||||
expect(model).to receive(:attribute).with(:sha256, an_instance_of(Gitlab::Database::Sha256Attribute))
|
||||
|
||||
model.sha256_attribute(:sha256)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -92,6 +92,7 @@ describe Key, :mailer do
|
|||
with_them do
|
||||
let!(:key) { create(factory) }
|
||||
let!(:original_fingerprint) { key.fingerprint }
|
||||
let!(:original_fingerprint_sha256) { key.fingerprint_sha256 }
|
||||
|
||||
it 'accepts a key with blank space characters after stripping them' do
|
||||
modified_key = key.key.insert(100, chars.first).insert(40, chars.last)
|
||||
|
|
@ -104,6 +105,8 @@ describe Key, :mailer do
|
|||
|
||||
expect(content).not_to match(/\s/)
|
||||
expect(original_fingerprint).to eq(key.fingerprint)
|
||||
expect(original_fingerprint).to eq(key.fingerprint_md5)
|
||||
expect(original_fingerprint_sha256).to eq(key.fingerprint_sha256)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ describe API::Keys do
|
|||
|
||||
it 'returns single ssh key with user information' do
|
||||
user.keys << key
|
||||
user.save
|
||||
get api("/keys/#{key.id}", admin)
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
expect(json_response['title']).to eq(key.title)
|
||||
|
|
@ -40,4 +39,73 @@ describe API::Keys do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /keys?fingerprint=' do
|
||||
it 'returns authentication error' do
|
||||
get api("/keys?fingerprint=#{key.fingerprint}")
|
||||
|
||||
expect(response).to have_gitlab_http_status(401)
|
||||
end
|
||||
|
||||
it 'returns authentication error when authenticated as user' do
|
||||
get api("/keys?fingerprint=#{key.fingerprint}", user)
|
||||
|
||||
expect(response).to have_gitlab_http_status(403)
|
||||
end
|
||||
|
||||
context 'when authenticated as admin' do
|
||||
it 'returns 404 for non-existing SSH md5 fingerprint' do
|
||||
get api("/keys?fingerprint=11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(404)
|
||||
expect(json_response['message']).to eq('404 Key Not Found')
|
||||
end
|
||||
|
||||
it 'returns 404 for non-existing SSH sha256 fingerprint' do
|
||||
get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:nUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo1lCg")}", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(404)
|
||||
expect(json_response['message']).to eq('404 Key Not Found')
|
||||
end
|
||||
|
||||
it 'returns user if SSH md5 fingerprint found' do
|
||||
user.keys << key
|
||||
|
||||
get api("/keys?fingerprint=#{key.fingerprint}", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
expect(json_response['title']).to eq(key.title)
|
||||
expect(json_response['user']['id']).to eq(user.id)
|
||||
expect(json_response['user']['username']).to eq(user.username)
|
||||
end
|
||||
|
||||
it 'returns user if SSH sha256 fingerprint found' do
|
||||
user.keys << key
|
||||
|
||||
get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:" + key.fingerprint_sha256)}", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
expect(json_response['title']).to eq(key.title)
|
||||
expect(json_response['user']['id']).to eq(user.id)
|
||||
expect(json_response['user']['username']).to eq(user.username)
|
||||
end
|
||||
|
||||
it 'returns user if SSH sha256 fingerprint found' do
|
||||
user.keys << key
|
||||
|
||||
get api("/keys?fingerprint=#{URI.encode_www_form_component("sha256:" + key.fingerprint_sha256)}", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
expect(json_response['title']).to eq(key.title)
|
||||
expect(json_response['user']['id']).to eq(user.id)
|
||||
expect(json_response['user']['username']).to eq(user.username)
|
||||
end
|
||||
|
||||
it "does not include the user's `is_admin` flag" do
|
||||
get api("/keys?fingerprint=#{key.fingerprint}", admin)
|
||||
|
||||
expect(json_response['user']['is_admin']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ describe Git::BranchPushService, services: true do
|
|||
end
|
||||
|
||||
it 'reports an error' do
|
||||
allow(Sidekiq).to receive(:server?).and_return(true)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
|
||||
expect(Sidekiq.logger).to receive(:warn)
|
||||
|
||||
expect { subject }.not_to change { Ci::Pipeline.count }
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ RSpec.shared_examples "redis_shared_examples" do
|
|||
|
||||
context 'when running not on sidekiq workers' do
|
||||
before do
|
||||
allow(Sidekiq).to receive(:server?).and_return(false)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(false)
|
||||
end
|
||||
|
||||
it 'instantiates a connection pool with size 5' do
|
||||
|
|
@ -130,7 +130,7 @@ RSpec.shared_examples "redis_shared_examples" do
|
|||
|
||||
context 'when running on sidekiq workers' do
|
||||
before do
|
||||
allow(Sidekiq).to receive(:server?).and_return(true)
|
||||
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
|
||||
allow(Sidekiq).to receive(:options).and_return({ concurrency: 18 })
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue