Commit c4045b32 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-09-06

# Conflicts:
#	app/models/clusters/platforms/kubernetes.rb
#	app/views/projects/blob/_blob.html.haml

[ci skip]
parents fcaf056f 4a14ff5b
...@@ -110,7 +110,9 @@ gem 'kaminari', '~> 1.0' ...@@ -110,7 +110,9 @@ gem 'kaminari', '~> 1.0'
gem 'hamlit', '~> 2.8.8' gem 'hamlit', '~> 2.8.8'
# Files attachments # Files attachments
gem 'carrierwave', '~> 1.2' # Locked until https://github.com/carrierwaveuploader/carrierwave/pull/2332/files is merged.
# config/initializers/carrierwave_patch.rb can be removed once that change is released.
gem 'carrierwave', '= 1.2.3'
gem 'mini_magick' gem 'mini_magick'
# Drag and Drop UI # Drag and Drop UI
......
...@@ -1026,7 +1026,7 @@ DEPENDENCIES ...@@ -1026,7 +1026,7 @@ DEPENDENCIES
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
capybara (~> 2.15) capybara (~> 2.15)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 1.2) carrierwave (= 1.2.3)
charlock_holmes (~> 0.7.5) charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2) chronic (~> 0.10.2)
chronic_duration (~> 0.10.6) chronic_duration (~> 0.10.6)
......
...@@ -1035,7 +1035,7 @@ DEPENDENCIES ...@@ -1035,7 +1035,7 @@ DEPENDENCIES
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
capybara (~> 2.15) capybara (~> 2.15)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 1.2) carrierwave (= 1.2.3)
charlock_holmes (~> 0.7.5) charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2) chronic (~> 0.10.2)
chronic_duration (~> 0.10.6) chronic_duration (~> 0.10.6)
......
app/assets/images/auth_buttons/azure_64.png

695 Bytes | W: | H:

app/assets/images/auth_buttons/azure_64.png

199 Bytes | W: | H:

app/assets/images/auth_buttons/azure_64.png
app/assets/images/auth_buttons/azure_64.png
app/assets/images/auth_buttons/azure_64.png
app/assets/images/auth_buttons/azure_64.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -63,7 +63,7 @@ export default { ...@@ -63,7 +63,7 @@ export default {
v-else v-else
role="button" role="button"
class="fa fa-times dropdown-input-search" class="fa fa-times dropdown-input-search"
@click="clearSearch" @click.stop.prevent="clearSearch"
></i> ></i>
</div> </div>
<div class="dropdown-content"> <div class="dropdown-content">
......
...@@ -229,8 +229,8 @@ ...@@ -229,8 +229,8 @@
svg { svg {
margin-bottom: 1px; margin-bottom: 1px;
height: 18px; height: $default-icon-size;
width: 18px; width: $default-icon-size;
border-radius: 50%; border-radius: 50%;
path { path {
......
...@@ -149,7 +149,8 @@ ...@@ -149,7 +149,8 @@
&.btn-success, &.btn-success,
&.btn-new, &.btn-new,
&.btn-create, &.btn-create,
&.btn-save { &.btn-save,
&.btn-register {
@include btn-green; @include btn-green;
} }
...@@ -172,8 +173,7 @@ ...@@ -172,8 +173,7 @@
} }
&.btn-info, &.btn-info,
&.btn-primary, &.btn-primary {
&.btn-register {
@include btn-blue; @include btn-blue;
} }
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
.btn-terminal { .btn-terminal {
svg { svg {
height: 14px; height: 14px;
width: 18px; width: $default-icon-size;
} }
} }
......
...@@ -216,8 +216,8 @@ ...@@ -216,8 +216,8 @@
vertical-align: inherit; vertical-align: inherit;
img { img {
height: 18px; height: $default-icon-size;
width: 18px; width: $default-icon-size;
} }
} }
......
...@@ -56,8 +56,8 @@ ...@@ -56,8 +56,8 @@
&, &,
.toggle-icon-svg { .toggle-icon-svg {
width: 18px; width: $default-icon-size;
height: 18px; height: $default-icon-size;
} }
.toggle-icon-svg { .toggle-icon-svg {
......
...@@ -252,7 +252,7 @@ $container-text-max-width: 540px; ...@@ -252,7 +252,7 @@ $container-text-max-width: 540px;
$gl-avatar-size: 40px; $gl-avatar-size: 40px;
$border-radius-default: 4px; $border-radius-default: 4px;
$border-radius-small: 2px; $border-radius-small: 2px;
$settings-icon-size: 18px; $default-icon-size: 18px;
$layout-link-gray: #7e7c7c; $layout-link-gray: #7e7c7c;
$btn-side-margin: 10px; $btn-side-margin: 10px;
$btn-sm-side-margin: 7px; $btn-sm-side-margin: 7px;
......
...@@ -749,6 +749,10 @@ ...@@ -749,6 +749,10 @@
left: $gl-padding; left: $gl-padding;
} }
.dropdown-input .dropdown-input-search {
pointer-events: all;
}
.diff-changed-file { .diff-changed-file {
display: flex; display: flex;
padding-top: 8px; padding-top: 8px;
......
...@@ -100,6 +100,22 @@ ...@@ -100,6 +100,22 @@
p { p {
margin: 0; margin: 0;
} }
.omniauth-btn {
margin-bottom: $gl-padding;
width: 48%;
padding: $gl-padding-8;
@include media-breakpoint-down(md) {
width: 100%;
}
img {
width: $default-icon-size;
height: $default-icon-size;
margin-right: $gl-padding;
}
}
} }
.new-session-tabs { .new-session-tabs {
...@@ -169,10 +185,6 @@ ...@@ -169,10 +185,6 @@
} }
} }
label {
font-weight: $gl-font-weight-normal;
}
.submit-container { .submit-container {
margin-top: 16px; margin-top: 16px;
} }
...@@ -200,15 +212,6 @@ ...@@ -200,15 +212,6 @@
} }
} }
.oauth-image-link {
margin-right: 10px;
img {
width: 32px;
height: 32px;
}
}
.devise-layout-html { .devise-layout-html {
margin: 0; margin: 0;
padding: 0; padding: 0;
......
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
.settings-list-icon { .settings-list-icon {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
font-size: $settings-icon-size; font-size: $default-icon-size;
line-height: 42px; line-height: 42px;
} }
......
module SendFileUpload module SendFileUpload
def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, disposition: 'attachment') def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, disposition: 'attachment')
if attachment if attachment
redirect_params[:query] = { "response-content-disposition" => "#{disposition};filename=#{attachment.inspect}" } # Response-Content-Type will not override an existing Content-Type in
# Google Cloud Storage, so the metadata needs to be cleared on GCS for
# this to work. However, this override works with AWS.
redirect_params[:query] = { "response-content-disposition" => "#{disposition};filename=#{attachment.inspect}",
"response-content-type" => guess_content_type(attachment) }
# By default, Rails will send uploads with an extension of .js with a # By default, Rails will send uploads with an extension of .js with a
# content-type of text/javascript, which will trigger Rails' # content-type of text/javascript, which will trigger Rails'
# cross-origin JavaScript protection. # cross-origin JavaScript protection.
...@@ -18,4 +22,14 @@ module SendFileUpload ...@@ -18,4 +22,14 @@ module SendFileUpload
redirect_to file_upload.url(**redirect_params) redirect_to file_upload.url(**redirect_params)
end end
end end
def guess_content_type(filename)
types = MIME::Types.type_for(filename)
if types.present?
types.first.content_type
else
"application/octet-stream"
end
end
end end
...@@ -6,8 +6,11 @@ module Clusters ...@@ -6,8 +6,11 @@ module Clusters
include Gitlab::Kubernetes include Gitlab::Kubernetes
include ReactiveCaching include ReactiveCaching
include EnumWithNil include EnumWithNil
<<<<<<< HEAD
prepend EE::KubernetesService prepend EE::KubernetesService
=======
>>>>>>> upstream/master
self.table_name = 'cluster_platforms_kubernetes' self.table_name = 'cluster_platforms_kubernetes'
self.reactive_cache_key = ->(kubernetes) { [kubernetes.class.model_name.singular, kubernetes.id] } self.reactive_cache_key = ->(kubernetes) { [kubernetes.class.model_name.singular, kubernetes.id] }
......
...@@ -36,6 +36,10 @@ class BuildDetailsEntity < JobEntity ...@@ -36,6 +36,10 @@ class BuildDetailsEntity < JobEntity
erase_project_job_path(project, build) erase_project_job_path(project, build)
end end
expose :terminal_path, if: -> (*) { can_create_build_terminal? } do |build|
terminal_project_job_path(project, build)
end
expose :merge_request, if: -> (*) { can?(current_user, :read_merge_request, build.merge_request) } do expose :merge_request, if: -> (*) { can?(current_user, :read_merge_request, build.merge_request) } do
expose :iid do |build| expose :iid do |build|
build.merge_request.iid build.merge_request.iid
...@@ -69,4 +73,8 @@ class BuildDetailsEntity < JobEntity ...@@ -69,4 +73,8 @@ class BuildDetailsEntity < JobEntity
def project def project
build.project build.project
end end
def can_create_build_terminal?
can?(current_user, :create_build_terminal, build) && build.has_terminal?
end
end end
= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors', 'aria-live' => 'assertive'}) do |f| = form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors', 'aria-live' => 'assertive'}) do |f|
.form-group .form-group
= f.label "Username or email", for: "user_login" = f.label "Username or email", for: "user_login", class: 'label-bold'
= f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required." = f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
.form-group .form-group
= f.label :password = f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", required: true, title: "This field is required." = f.password_field :password, class: "form-control bottom", required: true, title: "This field is required."
- if devise_mapping.rememberable? - if devise_mapping.rememberable?
.remember-me .remember-me
......
.omniauth-container .omniauth-container.prepend-top-15
%p %label.label-bold.d-block
%span.light Sign in with
Sign in with &nbsp;
- providers = enabled_button_based_providers - providers = enabled_button_based_providers
.d-flex.justify-content-between.flex-wrap
- providers.each do |provider| - providers.each do |provider|
%span.light
- has_icon = provider_has_icon?(provider) - has_icon = provider_has_icon?(provider)
= link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: 'oauth-login' + (has_icon ? ' oauth-image-link' : ' btn'), id: "oauth-login-#{provider}" = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'btn d-flex align-items-center omniauth-btn text-left oauth-login', id: "oauth-login-#{provider}" do
%fieldset.prepend-top-10.remember-me - if has_icon
= provider_image_tag(provider)
%span
= label_for_provider(provider)
%fieldset.remember-me
%label %label
= check_box_tag :remember_me, nil, false, class: 'remember-me-checkbox' = check_box_tag :remember_me, nil, false, class: 'remember-me-checkbox'
%span %span
......
...@@ -4,24 +4,24 @@ ...@@ -4,24 +4,24 @@
.devise-errors .devise-errors
= devise_error_messages! = devise_error_messages!
.form-group .form-group
= f.label :name, 'Full name' = f.label :name, 'Full name', class: 'label-bold'
= f.text_field :name, class: "form-control top", required: true, title: "This field is required." = f.text_field :name, class: "form-control top", required: true, title: "This field is required."
.username.form-group .username.form-group
= f.label :username = f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: 'Please create a username with only alphanumeric characters.' = f.text_field :username, class: "form-control middle", pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: 'Please create a username with only alphanumeric characters.'
%p.validation-error.hide Username is already taken. %p.validation-error.hide Username is already taken.
%p.validation-success.hide Username is available. %p.validation-success.hide Username is available.
%p.validation-pending.hide Checking username availability... %p.validation-pending.hide Checking username availability...
.form-group .form-group
= f.label :email = f.label :email, class: 'label-bold'
= f.email_field :email, class: "form-control middle", required: true, title: "Please provide a valid email address." = f.email_field :email, class: "form-control middle", required: true, title: "Please provide a valid email address."
.form-group .form-group
= f.label :email_confirmation = f.label :email_confirmation, class: 'label-bold'
= f.email_field :email_confirmation, class: "form-control middle", required: true, title: "Please retype the email address." = f.email_field :email_confirmation, class: "form-control middle", required: true, title: "Please retype the email address."
.form-group.append-bottom-20#password-strength .form-group.append-bottom-20#password-strength
= f.label :password = f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters." = f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters."
%p.gl-field-hint Minimum length is #{@minimum_password_length} characters %p.gl-field-hint.text-secondary Minimum length is #{@minimum_password_length} characters
- if Gitlab::CurrentSettings.current_application_settings.enforce_terms? - if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
.form-group .form-group
= check_box_tag :terms_opt_in, '1', false, required: true = check_box_tag :terms_opt_in, '1', false, required: true
...@@ -35,8 +35,3 @@ ...@@ -35,8 +35,3 @@
= recaptcha_tags = recaptcha_tags
.submit-container .submit-container
= f.submit "Register", class: "btn-register btn" = f.submit "Register", class: "btn-register btn"
.clearfix.submit-container
%p
%span.light Didn't receive a confirmation email?
= succeed '.' do
= link_to "Request a new one", new_confirmation_path(:user)
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
= f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9' }, = f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9' },
help: "Your name was automatically set based on your #{ attribute_provider_label(:name) } account, so people you know can recognize you." help: "Your name was automatically set based on your #{ attribute_provider_label(:name) } account, so people you know can recognize you."
- else - else
= f.text_field :name, required: true, wrapper: { class: 'col-md-9' }, help: "Enter your name, so people you know can recognize you." = f.text_field :name, label: 'Full name', required: true, wrapper: { class: 'col-md-9' }, help: "Enter your name, so people you know can recognize you."
= f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' } = f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' }
- if @user.read_only_attribute?(:email) - if @user.read_only_attribute?(:email)
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
.well-segment .well-segment
%ul.blob-commit-info %ul.blob-commit-info
= render 'projects/commits/commit', commit: @last_commit, project: @project, ref: @ref = render 'projects/commits/commit', commit: @last_commit, project: @project, ref: @ref
<<<<<<< HEAD
=======
>>>>>>> upstream/master
= render_if_exists 'projects/blob/owners', blob: blob = render_if_exists 'projects/blob/owners', blob: blob
= render "projects/blob/auxiliary_viewer", blob: blob = render "projects/blob/auxiliary_viewer", blob: blob
......
---
title: Update presentation for SSO providers on log in page
merge_request: 21233
author:
type: other
---
title: Make MR diff file filter input Clear button functional
merge_request: 21556
author:
type: fixed
---
title: Add terminal_path to job API response
merge_request: 21537
author:
type: other
---
title: 'Support a custom action, such as proxying to another server, after /api/v4/internal/allowed check succeeds'
merge_request: 21034
author:
type: changed
---
title: Add git_v2 feature flag
merge_request: 21520
author:
type: added
---
title: Fix attachments not displaying inline with Google Cloud Storage
merge_request: 21265
author:
type: fixed
# This monkey patches CarrierWave 1.2.3 to make Google Cloud Storage work with
# extra query parameters:
# https://github.com/carrierwaveuploader/carrierwave/pull/2332/files
module CarrierWave
module Storage
class Fog < Abstract
class File
def authenticated_url(options = {})
if %w(AWS Google Rackspace OpenStack).include?(@uploader.fog_credentials[:provider])
# avoid a get by using local references
local_directory = connection.directories.new(key: @uploader.fog_directory)
local_file = local_directory.files.new(key: path)
expire_at = ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
case @uploader.fog_credentials[:provider]
when 'AWS', 'Google'
local_file.url(expire_at, options)
when 'Rackspace'
connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
when 'OpenStack'
connection.get_object_https_url(@uploader.fog_directory, path, expire_at)
else
local_file.url(expire_at)
end
end
end
end
end
end
end
...@@ -9,7 +9,7 @@ module Fog ...@@ -9,7 +9,7 @@ module Fog
module MonkeyPatch module MonkeyPatch
def url(expires, options = {}) def url(expires, options = {})
requires :key requires :key
collection.get_https_url(key, expires) collection.get_https_url(key, expires, options)
end end
end end
......
...@@ -6,8 +6,17 @@ module API ...@@ -6,8 +6,17 @@ module API
helpers ::API::Helpers::InternalHelpers helpers ::API::Helpers::InternalHelpers
helpers ::Gitlab::Identifier helpers ::Gitlab::Identifier
UNKNOWN_CHECK_RESULT_ERROR = 'Unknown check result'.freeze
helpers do
def response_with_status(code: 200, success: true, message: nil, **extra_options)
status code
{ status: success, message: message }.merge(extra_options).compact
end
end
namespace 'internal' do namespace 'internal' do
# Check if git command is allowed to project # Check if git command is allowed for project
# #
# Params: # Params:
# key_id - ssh key id for Git over SSH # key_id - ssh key id for Git over SSH
...@@ -18,8 +27,6 @@ module API ...@@ -18,8 +27,6 @@ module API
# action - git action (git-upload-pack or git-receive-pack) # action - git action (git-upload-pack or git-receive-pack)
# changes - changes as "oldrev newrev ref", see Gitlab::ChangesList # changes - changes as "oldrev newrev ref", see Gitlab::ChangesList
post "/allowed" do post "/allowed" do
status 200
# Stores some Git-specific env thread-safely # Stores some Git-specific env thread-safely
env = parse_env env = parse_env
Gitlab::Git::HookEnv.set(gl_repository, env) if project Gitlab::Git::HookEnv.set(gl_repository, env) if project
...@@ -49,17 +56,21 @@ module API ...@@ -49,17 +56,21 @@ module API
namespace_path: namespace_path, project_path: project_path, namespace_path: namespace_path, project_path: project_path,
redirected_path: redirected_path) redirected_path: redirected_path)
begin check_result = begin
access_checker.check(params[:action], params[:changes]) result = access_checker.check(params[:action], params[:changes])
@project ||= access_checker.project @project ||= access_checker.project
rescue Gitlab::GitAccess::UnauthorizedError, Gitlab::GitAccess::NotFoundError => e result
break { status: false, message: e.message } rescue Gitlab::GitAccess::UnauthorizedError => e
break response_with_status(code: 401, success: false, message: e.message)
rescue Gitlab::GitAccess::NotFoundError => e
break response_with_status(code: 404, success: false, message: e.message)
end end
log_user_activity(actor) log_user_activity(actor)
{ case check_result
status: true, when ::Gitlab::GitAccessResult::Success
payload = {
gl_repository: gl_repository, gl_repository: gl_repository,
gl_id: Gitlab::GlId.gl_id(user), gl_id: Gitlab::GlId.gl_id(user),
gl_username: user&.username, gl_username: user&.username,
...@@ -70,6 +81,12 @@ module API ...@@ -70,6 +81,12 @@ module API
gitaly: gitaly_payload(params[:action]) gitaly: gitaly_payload(params[:action])
} }
response_with_status(**payload)
when ::Gitlab::GitAccessResult::CustomAction
response_with_status(code: 300, message: check_result.message, payload: check_result.payload)
else
response_with_status(code: 500, success: false, message: UNKNOWN_CHECK_RESULT_ERROR)
end
end end
post "/lfs_authenticate" do post "/lfs_authenticate" do
......
...@@ -53,6 +53,10 @@ module Gitlab ...@@ -53,6 +53,10 @@ module Gitlab
check_authentication_abilities!(cmd) check_authentication_abilities!(cmd)
check_command_disabled!(cmd) check_command_disabled!(cmd)
check_command_existence!(cmd) check_command_existence!(cmd)
custom_action = check_custom_action(cmd)
return custom_action if custom_action
check_db_accessibility!(cmd) check_db_accessibility!(cmd)
ensure_project_on_push!(cmd, changes) ensure_project_on_push!(cmd, changes)
...@@ -68,7 +72,7 @@ module Gitlab ...@@ -68,7 +72,7 @@ module Gitlab
check_push_access! check_push_access!
end end
true ::Gitlab::GitAccessResult::Success.new
end end
def guest_can_download_code? def guest_can_download_code?
...@@ -95,6 +99,10 @@ module Gitlab ...@@ -95,6 +99,10 @@ module Gitlab
private private
def check_custom_action(cmd)
nil
end
def check_valid_actor! def check_valid_actor!
return unless actor.is_a?(Key) return unless actor.is_a?(Key)
......
# frozen_string_literal: true
module Gitlab
module GitAccessResult
class CustomAction
attr_reader :payload, :message
# Example of payload:
#
# {
# 'action' => 'geo_proxy_to_primary',
# 'data' => {
# 'api_endpoints' => %w{geo/proxy_git_push_ssh/info_refs geo/proxy_git_push_ssh/push},
# 'gl_username' => user.username,
# 'primary_repo' => geo_primary_http_url_to_repo(project_or_wiki)
# }
# }
#
def initialize(payload, message)
@payload = payload
@message = message
end
end
end
end
# frozen_string_literal: true
module Gitlab
module GitAccessResult
class Success
end
end
end
...@@ -206,7 +206,7 @@ module Gitlab ...@@ -206,7 +206,7 @@ module Gitlab
result result
end end
SERVER_FEATURE_FLAGS = %w[gogit_findcommit].freeze SERVER_FEATURE_FLAGS = %w[gogit_findcommit git_v2].freeze
def self.server_feature_flags def self.server_feature_flags
SERVER_FEATURE_FLAGS.map do |f| SERVER_FEATURE_FLAGS.map do |f|
......
...@@ -158,7 +158,7 @@ module ObjectStorage ...@@ -158,7 +158,7 @@ module ObjectStorage
end end
def upload_options def upload_options
{ 'Content-Type' => 'application/octet-stream' } {}
end end
def connection def connection
......
...@@ -52,7 +52,7 @@ describe SendFileUpload do ...@@ -52,7 +52,7 @@ describe SendFileUpload do
end end
context 'with attachment' do context 'with attachment' do
subject { controller.send_upload(uploader, attachment: 'test.js') } let(:send_attachment) { controller.send_upload(uploader, attachment: 'test.js') }
it 'sends a file with content-type of text/plain' do it 'sends a file with content-type of text/plain' do
expected_params = { expected_params = {
...@@ -62,7 +62,29 @@ describe SendFileUpload do ...@@ -62,7 +62,29 @@ describe SendFileUpload do
} }
expect(controller).to receive(:send_file).with(uploader.path, expected_params) expect(controller).to receive(:send_file).with(uploader.path, expected_params)
subject send_attachment
end
context 'with a proxied file in object storage' do
before do
stub_uploads_object_storage(uploader: uploader_class)
uploader.object_store = ObjectStorage::Store::REMOTE
uploader.store!(temp_file)
allow(Gitlab.config.uploads.object_store).to receive(:proxy_download) { true }
end
it 'sends a file with a custom type' do
headers = double
expected_headers = %r(response-content-disposition=attachment%3Bfilename%3D%22test.js%22&response-content-type=application/javascript)
expect(Gitlab::Workhorse).to receive(:send_url).with(expected_headers).and_call_original
expect(headers).to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-url:/)
expect(controller).not_to receive(:send_file)
expect(controller).to receive(:headers) { headers }
expect(controller).to receive(:head).with(:ok)
send_attachment
end
end end
end end
...@@ -80,7 +102,12 @@ describe SendFileUpload do ...@@ -80,7 +102,12 @@ describe SendFileUpload do
it 'sends a file' do it 'sends a file' do
headers = double headers = double
expect(Gitlab::Workhorse).not_to receive(:send_url).with(/response-content-disposition/)
expect(Gitlab::Workhorse).not_to receive(:send_url).with(/response-content-type/)
expect(Gitlab::Workhorse).to receive(:send_url).and_call_original
expect(headers).to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-url:/) expect(headers).to receive(:store).with(Gitlab::Workhorse::SEND_DATA_HEADER, /^send-url:/)
expect(controller).not_to receive(:send_file)
expect(controller).to receive(:headers) { headers } expect(controller).to receive(:headers) { headers }
expect(controller).to receive(:head).with(:ok) expect(controller).to receive(:head).with(:ok)
......
...@@ -135,7 +135,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do ...@@ -135,7 +135,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end end
end end
context 'when requesting JSON with failed job' do context 'when requesting JSON' do
let(:merge_request) { create(:merge_request, source_project: project) } let(:merge_request) { create(:merge_request, source_project: project) }
before do before do
...@@ -147,28 +147,20 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do ...@@ -147,28 +147,20 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
get_show(id: job.id, format: :json) get_show(id: job.id, format: :json)
end end
context 'when job failed' do
it 'exposes needed information' do it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details') expect(response).to match_response_schema('job/job_details')
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z}) expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z})
expect(json_response['merge_request']['path']).to match(%r{merge_requests/\d+\z}) expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z})
expect(json_response['new_issue_path']).to include('/issues/new') expect(json_response['new_issue_path']).to include('/issues/new')
end end
end end
context 'when request JSON for successful job' do context 'when job has artifacts' do
let(:merge_request) { create(:merge_request, source_project: project) } context 'with not expiry date' do
let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) } let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
before do
project.add_developer(user)
sign_in(user)
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
get_show(id: job.id, format: :json)
end
it 'exposes needed information' do it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details') expect(response).to match_response_schema('job/job_details')
...@@ -176,23 +168,12 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do ...@@ -176,23 +168,12 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse}) expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
expect(json_response['artifact']).not_to have_key(:expired) expect(json_response['artifact']).not_to have_key(:expired)
expect(json_response['artifact']).not_to have_key(:expired_at) expect(json_response['artifact']).not_to have_key(:expired_at)
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z}) end
expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z})
end end
context 'when request JSON for successful job with expired artifacts' do context 'with expiry date' do
let(:merge_request) { create(:merge_request, source_project: project) }
let(:job) { create(:ci_build, :success, :artifacts, :expired, pipeline: pipeline) } let(:job) { create(:ci_build, :success, :artifacts, :expired, pipeline: pipeline) }
before do
project.add_developer(user)
sign_in(user)
allow_any_instance_of(Ci::Build).to receive(:merge_request).and_return(merge_request)
get_show(id: job.id, format: :json)
end
it 'exposes needed information' do it 'exposes needed information' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details') expect(response).to match_response_schema('job/job_details')
...@@ -200,8 +181,17 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do ...@@ -200,8 +181,17 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(json_response['artifact']).not_to have_key(:browse_path) expect(json_response['artifact']).not_to have_key(:browse_path)
expect(json_response['artifact']['expired']).to eq(true) expect(json_response['artifact']['expired']).to eq(true)
expect(json_response['artifact']['expire_at']).not_to be_empty expect(json_response['artifact']['expire_at']).not_to be_empty
expect(json_response['raw_path']).to match(%r{jobs/\d+/raw\z}) end
expect(json_response.dig('merge_request', 'path')).to match(%r{merge_requests/\d+\z}) end
end
context 'when job has terminal' do
let(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline) }
it 'exposes the terminal path' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('job/job_details')
expect(json_response['terminal_path']).to match(%r{/terminal})
end end
end end
end end
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
"allOf": [{ "$ref": "job.json" }], "allOf": [{ "$ref": "job.json" }],
"description": "An extension of job.json with more detailed information", "description": "An extension of job.json with more detailed information",
"properties": { "properties": {
"artifact": { "$ref": "artifact.json" } "artifact": { "$ref": "artifact.json" },
"terminal_path": { "type": "string" }
} }
} }
...@@ -62,7 +62,7 @@ describe ObjectStorage::DirectUpload do ...@@ -62,7 +62,7 @@ describe ObjectStorage::DirectUpload do
expect(subject[:StoreURL]).to start_with(storage_url) expect(subject[:StoreURL]).to start_with(storage_url)
expect(subject[:DeleteURL]).to start_with(storage_url) expect(subject[:DeleteURL]).to start_with(storage_url)
expect(subject[:CustomPutHeaders]).to be_truthy expect(subject[:CustomPutHeaders]).to be_truthy
expect(subject[:PutHeaders]).to eq({ 'Content-Type' => 'application/octet-stream' }) expect(subject[:PutHeaders]).to eq({})
end end
end end
......
...@@ -381,7 +381,7 @@ describe API::Internal do ...@@ -381,7 +381,7 @@ describe API::Internal do
it do it do
pull(key, project) pull(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(401)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
expect(user.reload.last_activity_on).to be_nil expect(user.reload.last_activity_on).to be_nil
end end
...@@ -391,13 +391,61 @@ describe API::Internal do ...@@ -391,13 +391,61 @@ describe API::Internal do
it do it do
push(key, project) push(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(401)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
expect(user.reload.last_activity_on).to be_nil expect(user.reload.last_activity_on).to be_nil
end end
end end
end end
context "custom action" do
let(:access_checker) { double(Gitlab::GitAccess) }
let(:message) { 'CustomActionError message' }
let(:payload) do
{
'action' => 'geo_proxy_to_primary',
'data' => {
'api_endpoints' => %w{geo/proxy_git_push_ssh/info_refs geo/proxy_git_push_ssh/push},
'gl_username' => 'testuser',
'primary_repo' => 'http://localhost:3000/testuser/repo.git'
}
}
end
let(:custom_action_result) { Gitlab::GitAccessResult::CustomAction.new(payload, message) }
before do
project.add_guest(user)
expect(Gitlab::GitAccess).to receive(:new).with(
key,
project,
'ssh',
{
authentication_abilities: [:read_project, :download_code, :push_code],
namespace_path: project.namespace.name,
project_path: project.path,
redirected_path: nil
}
).and_return(access_checker)
expect(access_checker).to receive(:check).with(
'git-receive-pack',
'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
).and_return(custom_action_result)
end
context "git push" do
it do
push(key, project)
expect(response).to have_gitlab_http_status(300)
expect(json_response['status']).to be_truthy
expect(json_response['message']).to eql(message)
expect(json_response['payload']).to eql(payload)
expect(user.reload.last_activity_on).to be_nil
end
end
end
context "blocked user" do context "blocked user" do
let(:personal_project) { create(:project, namespace: user.namespace) } let(:personal_project) { create(:project, namespace: user.namespace) }
...@@ -409,7 +457,7 @@ describe API::Internal do ...@@ -409,7 +457,7 @@ describe API::Internal do
it do it do
pull(key, personal_project) pull(key, personal_project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(401)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
expect(user.reload.last_activity_on).to be_nil expect(user.reload.last_activity_on).to be_nil
end end
...@@ -419,7 +467,7 @@ describe API::Internal do ...@@ -419,7 +467,7 @@ describe API::Internal do
it do it do
push(key, personal_project) push(key, personal_project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(401)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
expect(user.reload.last_activity_on).to be_nil expect(user.reload.last_activity_on).to be_nil
end end
...@@ -445,7 +493,7 @@ describe API::Internal do ...@@ -445,7 +493,7 @@ describe API::Internal do
it do it do
push(key, project) push(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(401)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
end end
end end
...@@ -477,7 +525,7 @@ describe API::Internal do ...@@ -477,7 +525,7 @@ describe API::Internal do
it do it do
archive(key, project) archive(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(404)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
end end
end end
...@@ -489,7 +537,7 @@ describe API::Internal do ...@@ -489,7 +537,7 @@ describe API::Internal do
pull(key, project) pull(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(404)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
end end
end end
...@@ -498,7 +546,7 @@ describe API::Internal do ...@@ -498,7 +546,7 @@ describe API::Internal do
it do it do
pull(OpenStruct.new(id: 0), project) pull(OpenStruct.new(id: 0), project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(404)
expect(json_response["status"]).to be_falsey expect(json_response["status"]).to be_falsey
end end
end end
...@@ -511,7 +559,7 @@ describe API::Internal do ...@@ -511,7 +559,7 @@ describe API::Internal do
it 'rejects the SSH push' do it 'rejects the SSH push' do
push(key, project) push(key, project)
expect(response.status).to eq(200) expect(response.status).to eq(401)
expect(json_response['status']).to be_falsey expect(json_response['status']).to be_falsey
expect(json_response['message']).to eq 'Git access over SSH is not allowed' expect(json_response['message']).to eq 'Git access over SSH is not allowed'
end end
...@@ -519,7 +567,7 @@ describe API::Internal do ...@@ -519,7 +567,7 @@ describe API::Internal do
it 'rejects the SSH pull' do it 'rejects the SSH pull' do
pull(key, project) pull(key, project)
expect(response.status).to eq(200) expect(response.status).to eq(401)
expect(json_response['status']).to be_falsey expect(json_response['status']).to be_falsey
expect(json_response['message']).to eq 'Git access over SSH is not allowed' expect(json_response['message']).to eq 'Git access over SSH is not allowed'
end end
...@@ -533,7 +581,7 @@ describe API::Internal do ...@@ -533,7 +581,7 @@ describe API::Internal do
it 'rejects the HTTP push' do it 'rejects the HTTP push' do
push(key, project, 'http') push(key, project, 'http')
expect(response.status).to eq(200) expect(response.status).to eq(401)
expect(json_response['status']).to be_falsey expect(json_response['status']).to be_falsey
expect(json_response['message']).to eq 'Git access over HTTP is not allowed' expect(json_response['message']).to eq 'Git access over HTTP is not allowed'
end end
...@@ -541,7 +589,7 @@ describe API::Internal do ...@@ -541,7 +589,7 @@ describe API::Internal do
it 'rejects the HTTP pull' do it 'rejects the HTTP pull' do
pull(key, project, 'http') pull(key, project, 'http')
expect(response.status).to eq(200) expect(response.status).to eq(401)
expect(json_response['status']).to be_falsey expect(json_response['status']).to be_falsey
expect(json_response['message']).to eq 'Git access over HTTP is not allowed' expect(json_response['message']).to eq 'Git access over HTTP is not allowed'
end end
...@@ -571,14 +619,14 @@ describe API::Internal do ...@@ -571,14 +619,14 @@ describe API::Internal do
it 'rejects the push' do it 'rejects the push' do
push(key, project) push(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(404)
expect(json_response['status']).to be_falsy expect(json_response['status']).to be_falsy
end end
it 'rejects the SSH pull' do it 'rejects the SSH pull' do
pull(key, project) pull(key, project)
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(404)
expect(json_response['status']).to be_falsy expect(json_response['status']).to be_falsy
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment