Commit d51bb99a authored by Rémy Coutable's avatar Rémy Coutable

Merge commit 'dev/security' into 'master'

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parents 7e493b11 3f57ea0c
...@@ -86,6 +86,14 @@ v 8.12.2 ...@@ -86,6 +86,14 @@ v 8.12.2
- Fix resolve discussion buttons endpoint path - Fix resolve discussion buttons endpoint path
- Refactor remnants of CoffeeScript destructured opts and super !6261 - Refactor remnants of CoffeeScript destructured opts and super !6261
v 8.12.4 (unreleased)
- Set GitLab project exported file permissions to owner only
- Don't send Private-Token (API authentication) headers to Sentry
v 8.12.2 (unreleased)
- Fix Import/Export not recognising correctly the imported services.
- Respect the fork_project permission when forking projects
v 8.12.1 v 8.12.1
- Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST - Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST
- Fix issue with search filter labels not displaying - Fix issue with search filter labels not displaying
......
...@@ -231,7 +231,7 @@ gem 'net-ssh', '~> 3.0.1' ...@@ -231,7 +231,7 @@ gem 'net-ssh', '~> 3.0.1'
gem 'base32', '~> 0.3.0' gem 'base32', '~> 0.3.0'
# Sentry integration # Sentry integration
gem 'sentry-raven', '~> 1.1.0' gem 'sentry-raven', '~> 2.0.0'
gem 'premailer-rails', '~> 1.9.0' gem 'premailer-rails', '~> 1.9.0'
......
...@@ -665,8 +665,8 @@ GEM ...@@ -665,8 +665,8 @@ GEM
activesupport (>= 3.1) activesupport (>= 3.1)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
thor (~> 0.14) thor (~> 0.14)
sentry-raven (1.1.0) sentry-raven (2.0.2)
faraday (>= 0.7.6) faraday (>= 0.7.6, < 0.10.x)
settingslogic (2.0.9) settingslogic (2.0.9)
sexp_processor (4.7.0) sexp_processor (4.7.0)
sham_rack (1.3.6) sham_rack (1.3.6)
...@@ -948,7 +948,7 @@ DEPENDENCIES ...@@ -948,7 +948,7 @@ DEPENDENCIES
sdoc (~> 0.3.20) sdoc (~> 0.3.20)
seed-fu (~> 2.3.5) seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
sentry-raven (~> 1.1.0) sentry-raven (~> 2.0.0)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
namespacesPath: "/api/:version/namespaces.json", namespacesPath: "/api/:version/namespaces.json",
groupProjectsPath: "/api/:version/groups/:id/projects.json", groupProjectsPath: "/api/:version/groups/:id/projects.json",
projectsPath: "/api/:version/projects.json?simple=true", projectsPath: "/api/:version/projects.json?simple=true",
labelsPath: "/api/:version/projects/:id/labels", labelsPath: "/:namespace_path/:project_path/labels",
licensePath: "/api/:version/licenses/:key", licensePath: "/api/:version/licenses/:key",
gitignorePath: "/api/:version/gitignores/:key", gitignorePath: "/api/:version/gitignores/:key",
gitlabCiYmlPath: "/api/:version/gitlab_ci_ymls/:key", gitlabCiYmlPath: "/api/:version/gitlab_ci_ymls/:key",
...@@ -66,13 +66,14 @@ ...@@ -66,13 +66,14 @@
return callback(projects); return callback(projects);
}); });
}, },
newLabel: function(project_id, data, callback) { newLabel: function(namespace_path, project_path, data, callback) {
var url = Api.buildUrl(Api.labelsPath) var url = Api.buildUrl(Api.labelsPath)
.replace(':id', project_id); .replace(':namespace_path', namespace_path)
.replace(':project_path', project_path);
return $.ajax({ return $.ajax({
url: url, url: url,
type: "POST", type: "POST",
data: data, data: {'label': data},
dataType: "json" dataType: "json"
}).done(function(label) { }).done(function(label) {
return callback(label); return callback(label);
......
...@@ -3,8 +3,7 @@ $(() => { ...@@ -3,8 +3,7 @@ $(() => {
$('.js-new-board-list').each(function () { $('.js-new-board-list').each(function () {
const $this = $(this); const $this = $(this);
new gl.CreateLabelDropdown($this.closest('.dropdown').find('.dropdown-new-label'), $this.data('namespace-path'), $this.data('project-path'));
new gl.CreateLabelDropdown($this.closest('.dropdown').find('.dropdown-new-label'), $this.data('project-id'));
$this.glDropdown({ $this.glDropdown({
data(term, callback) { data(term, callback) {
......
(function (w) { (function (w) {
class CreateLabelDropdown { class CreateLabelDropdown {
constructor ($el, projectId) { constructor ($el, namespacePath, projectPath) {
this.$el = $el; this.$el = $el;
this.projectId = projectId; this.namespacePath = namespacePath;
this.projectPath = projectPath;
this.$dropdownBack = $('.dropdown-menu-back', this.$el.closest('.dropdown')); this.$dropdownBack = $('.dropdown-menu-back', this.$el.closest('.dropdown'));
this.$cancelButton = $('.js-cancel-label-btn', this.$el); this.$cancelButton = $('.js-cancel-label-btn', this.$el);
this.$newLabelField = $('#new_label_name', this.$el); this.$newLabelField = $('#new_label_name', this.$el);
...@@ -91,8 +92,8 @@ ...@@ -91,8 +92,8 @@
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
Api.newLabel(this.projectId, { Api.newLabel(this.namespacePath, this.projectPath, {
name: this.$newLabelField.val(), title: this.$newLabelField.val(),
color: this.$newColorField.val() color: this.$newColorField.val()
}, (label) => { }, (label) => {
this.$newLabelCreateButton.enable(); this.$newLabelCreateButton.enable();
......
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, projectId, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove; var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, projectId, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove;
$dropdown = $(dropdown); $dropdown = $(dropdown);
$toggleText = $dropdown.find('.dropdown-toggle-text'); $toggleText = $dropdown.find('.dropdown-toggle-text');
projectId = $dropdown.data('project-id'); namespacePath = $dropdown.data('namespace-path');
projectPath = $dropdown.data('project-path');
labelUrl = $dropdown.data('labels'); labelUrl = $dropdown.data('labels');
issueUpdateURL = $dropdown.data('issueUpdate'); issueUpdateURL = $dropdown.data('issueUpdate');
selectedLabel = $dropdown.data('selected'); selectedLabel = $dropdown.data('selected');
...@@ -45,7 +46,7 @@ ...@@ -45,7 +46,7 @@
$sidebarLabelTooltip.tooltip(); $sidebarLabelTooltip.tooltip();
if ($dropdown.closest('.dropdown').find('.dropdown-new-label').length) { if ($dropdown.closest('.dropdown').find('.dropdown-new-label').length) {
new gl.CreateLabelDropdown($dropdown.closest('.dropdown').find('.dropdown-new-label'), projectId); new gl.CreateLabelDropdown($dropdown.closest('.dropdown').find('.dropdown-new-label'), namespacePath, projectPath);
} }
saveLabelData = function() { saveLabelData = function() {
......
...@@ -30,9 +30,15 @@ class Projects::LabelsController < Projects::ApplicationController ...@@ -30,9 +30,15 @@ class Projects::LabelsController < Projects::ApplicationController
@label = @project.labels.create(label_params) @label = @project.labels.create(label_params)
if @label.valid? if @label.valid?
redirect_to namespace_project_labels_path(@project.namespace, @project) respond_to do |format|
format.html { redirect_to namespace_project_labels_path(@project.namespace, @project) }
format.json { render json: @label }
end
else else
render 'new' respond_to do |format|
format.html { render 'new' }
format.json { render json: { message: @label.errors.messages }, status: 400 }
end
end end
end end
......
...@@ -17,6 +17,11 @@ module Projects ...@@ -17,6 +17,11 @@ module Projects
return @project return @project
end end
unless allowed_fork?(forked_from_project_id)
@project.errors.add(:forked_from_project_id, 'is forbidden')
return @project
end
# Set project name from path # Set project name from path
if @project.name.present? && @project.path.present? if @project.name.present? && @project.path.present?
# if both name and path set - everything is ok # if both name and path set - everything is ok
...@@ -73,6 +78,13 @@ module Projects ...@@ -73,6 +78,13 @@ module Projects
@project.errors.add(:namespace, "is not valid") @project.errors.add(:namespace, "is not valid")
end end
def allowed_fork?(source_project_id)
return true if source_project_id.nil?
source_project = Project.find_by(id: source_project_id)
current_user.can?(:fork_project, source_project)
end
def allowed_namespace?(user, namespace_id) def allowed_namespace?(user, namespace_id)
namespace = Namespace.find_by(id: namespace_id) namespace = Namespace.find_by(id: namespace_id)
current_user.can?(:create_projects, namespace) current_user.can?(:create_projects, namespace)
......
...@@ -16,6 +16,8 @@ module Projects ...@@ -16,6 +16,8 @@ module Projects
end end
new_project = CreateService.new(current_user, new_params).execute new_project = CreateService.new(current_user, new_params).execute
return new_project unless new_project.persisted?
builds_access_level = @project.project_feature.builds_access_level builds_access_level = @project.project_feature.builds_access_level
new_project.project_feature.update_attributes(builds_access_level: builds_access_level) new_project.project_feature.update_attributes(builds_access_level: builds_access_level)
......
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
%tr %tr
%td #{stage.capitalize} Job - #{build[:name]} %td #{stage.capitalize} Job - #{build[:name]}
%td %td
%pre %pre= build[:commands]
= simple_format build[:commands]
%br %br
%b Tag list: %b Tag list:
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
%input.pull-left.form-control{ type: "search", placeholder: "Filter by name...", "v-model" => "filters.search", "debounce" => "250" } %input.pull-left.form-control{ type: "search", placeholder: "Filter by name...", "v-model" => "filters.search", "debounce" => "250" }
- if can?(current_user, :admin_list, @project) - if can?(current_user, :admin_list, @project)
.dropdown.pull-right .dropdown.pull-right
%button.btn.btn-create.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, project_id: @project.try(:id) } } %button.btn.btn-create.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } }
Create new list Create new list
.dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable .dropdown-menu.dropdown-menu-paging.dropdown-menu-align-right.dropdown-menu-issues-board-new.dropdown-menu-selectable
= render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Create a new list" } = render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Create a new list" }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
- classes = local_assigns.fetch(:classes, []) - classes = local_assigns.fetch(:classes, [])
- selected = local_assigns.fetch(:selected, nil) - selected = local_assigns.fetch(:selected, nil)
- selected_toggle = local_assigns.fetch(:selected_toggle, nil) - selected_toggle = local_assigns.fetch(:selected_toggle, nil)
- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", project_id: project.try(:id), labels: labels_filter_path, default_label: "Labels"} - dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path), labels: labels_filter_path, default_label: "Labels"}
- dropdown_data.merge!(data_options) - dropdown_data.merge!(data_options)
- classes << 'js-extra-options' if extra_options - classes << 'js-extra-options' if extra_options
- classes << 'js-filter-submit' if filter_submit - classes << 'js-filter-submit' if filter_submit
......
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
- selected_labels.each do |label| - selected_labels.each do |label|
= hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil = hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil
.dropdown .dropdown
%button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", project_id: (@project.id if @project), issue_update: issuable_json_path(issuable), labels: (namespace_project_labels_path(@project.namespace, @project, :json) if @project)}} %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (namespace_project_labels_path(@project.namespace, @project, :json) if @project)}}
%span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?)} %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?)}
= multi_label_name(selected_labels, "Labels") = multi_label_name(selected_labels, "Labels")
= icon('chevron-down') = icon('chevron-down')
......
...@@ -50,6 +50,7 @@ module Gitlab ...@@ -50,6 +50,7 @@ module Gitlab
# - Build variables (:variables) # - Build variables (:variables)
# - GitLab Pages SSL cert/key info (:certificate, :encrypted_key) # - GitLab Pages SSL cert/key info (:certificate, :encrypted_key)
# - Webhook URLs (:hook) # - Webhook URLs (:hook)
# - GitLab-shell secret token (:secret_token)
# - Sentry DSN (:sentry_dsn) # - Sentry DSN (:sentry_dsn)
# - Deploy keys (:key) # - Deploy keys (:key)
config.filter_parameters += %i( config.filter_parameters += %i(
...@@ -62,6 +63,7 @@ module Gitlab ...@@ -62,6 +63,7 @@ module Gitlab
password password
password_confirmation password_confirmation
private_token private_token
secret_token
sentry_dsn sentry_dsn
variables variables
) )
......
...@@ -18,6 +18,8 @@ if Rails.env.production? ...@@ -18,6 +18,8 @@ if Rails.env.production?
# Sanitize fields based on those sanitized from Rails. # Sanitize fields based on those sanitized from Rails.
config.sanitize_fields = Rails.application.config.filter_parameters.map(&:to_s) config.sanitize_fields = Rails.application.config.filter_parameters.map(&:to_s)
# Sanitize authentication headers
config.sanitize_http_headers = %w[Authorization Private-Token]
config.tags = { program: Gitlab::Sentry.program_context } config.tags = { program: Gitlab::Sentry.program_context }
end end
end end
......
...@@ -70,6 +70,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps ...@@ -70,6 +70,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
step 'There is an existent fork of the "Shop" project' do step 'There is an existent fork of the "Shop" project' do
user = create(:user, name: 'Mike') user = create(:user, name: 'Mike')
@project.team << [user, :reporter]
@forked_project = Projects::ForkService.new(@project, user).execute @forked_project = Projects::ForkService.new(@project, user).execute
end end
......
...@@ -21,8 +21,11 @@ module API ...@@ -21,8 +21,11 @@ module API
end end
# Check the Rails session for valid authentication details # Check the Rails session for valid authentication details
#
# Until CSRF protection is added to the API, disallow this method for
# state-changing endpoints
def find_user_from_warden def find_user_from_warden
warden ? warden.authenticate : nil warden.try(:authenticate) if request.get? || request.head?
end end
def find_user_by_private_token def find_user_by_private_token
......
module Gitlab module Gitlab
module ImportExport module ImportExport
module CommandLineUtil module CommandLineUtil
DEFAULT_MODE = 0700
def tar_czf(archive:, dir:) def tar_czf(archive:, dir:)
tar_with_options(archive: archive, dir: dir, options: 'czf') tar_with_options(archive: archive, dir: dir, options: 'czf')
end end
...@@ -21,6 +23,11 @@ module Gitlab ...@@ -21,6 +23,11 @@ module Gitlab
execute(%W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args) execute(%W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args)
end end
def mkdir_p(path)
FileUtils.mkdir_p(path, mode: DEFAULT_MODE)
FileUtils.chmod(DEFAULT_MODE, path)
end
private private
def tar_with_options(archive:, dir:, options:) def tar_with_options(archive:, dir:, options:)
...@@ -45,7 +52,7 @@ module Gitlab ...@@ -45,7 +52,7 @@ module Gitlab
# if we are copying files, create the destination folder # if we are copying files, create the destination folder
destination_folder = File.file?(source) ? File.dirname(destination) : destination destination_folder = File.file?(source) ? File.dirname(destination) : destination
FileUtils.mkdir_p(destination_folder) mkdir_p(destination_folder)
FileUtils.copy_entry(source, destination) FileUtils.copy_entry(source, destination)
true true
end end
......
...@@ -15,7 +15,7 @@ module Gitlab ...@@ -15,7 +15,7 @@ module Gitlab
end end
def import def import
FileUtils.mkdir_p(@shared.export_path) mkdir_p(@shared.export_path)
wait_for_archived_file do wait_for_archived_file do
decompress_archive decompress_archive
......
module Gitlab module Gitlab
module ImportExport module ImportExport
class ProjectTreeSaver class ProjectTreeSaver
include Gitlab::ImportExport::CommandLineUtil
attr_reader :full_path attr_reader :full_path
def initialize(project:, shared:) def initialize(project:, shared:)
...@@ -10,7 +12,7 @@ module Gitlab ...@@ -10,7 +12,7 @@ module Gitlab
end end
def save def save
FileUtils.mkdir_p(@shared.export_path) mkdir_p(@shared.export_path)
File.write(full_path, project_json_tree) File.write(full_path, project_json_tree)
true true
......
...@@ -12,7 +12,7 @@ module Gitlab ...@@ -12,7 +12,7 @@ module Gitlab
def restore def restore
return true unless File.exist?(@path_to_bundle) return true unless File.exist?(@path_to_bundle)
FileUtils.mkdir_p(path_to_repo) mkdir_p(path_to_repo)
git_unbundle(repo_path: path_to_repo, bundle_path: @path_to_bundle) && repo_restore_hooks git_unbundle(repo_path: path_to_repo, bundle_path: @path_to_bundle) && repo_restore_hooks
rescue => e rescue => e
......
...@@ -20,7 +20,7 @@ module Gitlab ...@@ -20,7 +20,7 @@ module Gitlab
private private
def bundle_to_disk def bundle_to_disk
FileUtils.mkdir_p(@shared.export_path) mkdir_p(@shared.export_path)
git_bundle(repo_path: path_to_repo, bundle_path: @full_path) git_bundle(repo_path: path_to_repo, bundle_path: @full_path)
rescue => e rescue => e
@shared.error(e) @shared.error(e)
......
module Gitlab module Gitlab
module ImportExport module ImportExport
class VersionSaver class VersionSaver
include Gitlab::ImportExport::CommandLineUtil
def initialize(shared:) def initialize(shared:)
@shared = shared @shared = shared
end end
def save def save
FileUtils.mkdir_p(@shared.export_path) mkdir_p(@shared.export_path)
File.write(version_file, Gitlab::ImportExport.version, mode: 'w') File.write(version_file, Gitlab::ImportExport.version, mode: 'w')
rescue => e rescue => e
......
...@@ -9,7 +9,7 @@ module Gitlab ...@@ -9,7 +9,7 @@ module Gitlab
end end
def bundle_to_disk(full_path) def bundle_to_disk(full_path)
FileUtils.mkdir_p(@shared.export_path) mkdir_p(@shared.export_path)
git_bundle(repo_path: path_to_repo, bundle_path: full_path) git_bundle(repo_path: path_to_repo, bundle_path: full_path)
rescue => e rescue => e
@shared.error(e) @shared.error(e)
......
...@@ -73,8 +73,8 @@ describe UsersController do ...@@ -73,8 +73,8 @@ describe UsersController do
end end
context 'forked project' do context 'forked project' do
let!(:project) { create(:project) } let(:project) { create(:project) }
let!(:forked_project) { Projects::ForkService.new(project, user).execute } let(:forked_project) { Projects::ForkService.new(project, user).execute }
before do before do
sign_in(user) sign_in(user)
......
...@@ -47,6 +47,8 @@ feature 'Import/Export - project export integration test', feature: true, js: tr ...@@ -47,6 +47,8 @@ feature 'Import/Export - project export integration test', feature: true, js: tr
expect(page).to have_content('Download export') expect(page).to have_content('Download export')
expect(file_permissions(project.export_path)).to eq(0700)
in_directory_with_expanded_export(project) do |exit_status, tmpdir| in_directory_with_expanded_export(project) do |exit_status, tmpdir|
expect(exit_status).to eq(0) expect(exit_status).to eq(0)
......
...@@ -11,7 +11,7 @@ describe ProjectsHelper do ...@@ -11,7 +11,7 @@ describe ProjectsHelper do
describe "can_change_visibility_level?" do describe "can_change_visibility_level?" do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { create(:user) } let(:user) { create(:project_member, :reporter, user: create(:user), project: project).user }
let(:fork_project) { Projects::ForkService.new(project, user).execute } let(:fork_project) { Projects::ForkService.new(project, user).execute }
it "returns false if there are no appropriate permissions" do it "returns false if there are no appropriate permissions" do
......
...@@ -6,6 +6,7 @@ describe ForkedProjectLink, "add link on fork" do ...@@ -6,6 +6,7 @@ describe ForkedProjectLink, "add link on fork" do
let(:user) { create(:user, namespace: namespace) } let(:user) { create(:user, namespace: namespace) }
before do before do
create(:project_member, :reporter, user: user, project: project_from)
@project_to = fork_project(project_from, user) @project_to = fork_project(project_from, user)
end end
......
...@@ -10,7 +10,8 @@ describe API::Helpers, api: true do ...@@ -10,7 +10,8 @@ describe API::Helpers, api: true do
let(:key) { create(:key, user: user) } let(:key) { create(:key, user: user) }
let(:params) { {} } let(:params) { {} }
let(:env) { {} } let(:env) { { 'REQUEST_METHOD' => 'GET' } }
let(:request) { Rack::Request.new(env) }
def set_env(token_usr, identifier) def set_env(token_usr, identifier)
clear_env clear_env
...@@ -52,17 +53,43 @@ describe API::Helpers, api: true do ...@@ -52,17 +53,43 @@ describe API::Helpers, api: true do
describe ".current_user" do describe ".current_user" do
subject { current_user } subject { current_user }
describe "when authenticating via Warden" do describe "Warden authentication" do
before { doorkeeper_guard_returns false } before { doorkeeper_guard_returns false }
context "fails" do context "with invalid credentials" do
it { is_expected.to be_nil } context "GET request" do
before { env['REQUEST_METHOD'] = 'GET' }
it { is_expected.to be_nil }
end
end end
context "succeeds" do context "with valid credentials" do
before { warden_authenticate_returns user } before { warden_authenticate_returns user }
it { is_expected.to eq(user) } context "GET request" do
before { env['REQUEST_METHOD'] = 'GET' }
it { is_expected.to eq(user) }
end
context "HEAD request" do
before { env['REQUEST_METHOD'] = 'HEAD' }
it { is_expected.to eq(user) }
end
context "PUT request" do
before { env['REQUEST_METHOD'] = 'PUT' }
it { is_expected.to be_nil }
end
context "POST request" do
before { env['REQUEST_METHOD'] = 'POST' }
it { is_expected.to be_nil }
end
context "DELETE request" do
before { env['REQUEST_METHOD'] = 'DELETE' }
it { is_expected.to be_nil }
end
end end
end end
......
...@@ -18,7 +18,7 @@ describe API::API, api: true do ...@@ -18,7 +18,7 @@ describe API::API, api: true do
end end
let(:project_user2) do let(:project_user2) do
create(:project_member, :guest, user: user2, project: project) create(:project_member, :reporter, user: user2, project: project)
end end
describe 'POST /projects/fork/:id' do describe 'POST /projects/fork/:id' do
......
...@@ -12,12 +12,26 @@ describe Projects::ForkService, services: true do ...@@ -12,12 +12,26 @@ describe Projects::ForkService, services: true do
description: 'wow such project') description: 'wow such project')
@to_namespace = create(:namespace) @to_namespace = create(:namespace)
@to_user = create(:user, namespace: @to_namespace) @to_user = create(:user, namespace: @to_namespace)
@from_project.add_user(@to_user, :developer)
end end
context 'fork project' do context 'fork project' do
context 'when forker is a guest' do
before do
@guest = create(:user)
@from_project.add_user(@guest, :guest)
end
subject { fork_project(@from_project, @guest) }
it { is_expected.not_to be_persisted }
it { expect(subject.errors[:forked_from_project_id]).to eq(['is forbidden']) }
end
describe "successfully creates project in the user namespace" do describe "successfully creates project in the user namespace" do
let(:to_project) { fork_project(@from_project, @to_user) } let(:to_project) { fork_project(@from_project, @to_user) }
it { expect(to_project).to be_persisted }
it { expect(to_project.errors).to be_empty }
it { expect(to_project.owner).to eq(@to_user) } it { expect(to_project.owner).to eq(@to_user) }
it { expect(to_project.namespace).to eq(@to_user.namespace) } it { expect(to_project.namespace).to eq(@to_user.namespace) }
it { expect(to_project.star_count).to be_zero } it { expect(to_project.star_count).to be_zero }
...@@ -29,7 +43,9 @@ describe Projects::ForkService, services: true do ...@@ -29,7 +43,9 @@ describe Projects::ForkService, services: true do
it "fails due to validation, not transaction failure" do it "fails due to validation, not transaction failure" do
@existing_project = create(:project, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace) @existing_project = create(:project, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace)
@to_project = fork_project(@from_project, @to_user) @to_project = fork_project(@from_project, @to_user)
expect(@existing_project.persisted?).to be_truthy expect(@existing_project).to be_persisted
expect(@to_project).not_to be_persisted
expect(@to_project.errors[:name]).to eq(['has already been taken']) expect(@to_project.errors[:name]).to eq(['has already been taken'])
expect(@to_project.errors[:path]).to eq(['has already been taken']) expect(@to_project.errors[:path]).to eq(['has already been taken'])
end end
...@@ -81,18 +97,23 @@ describe Projects::ForkService, services: true do ...@@ -81,18 +97,23 @@ describe Projects::ForkService, services: true do
@group = create(:group) @group = create(:group)
@group.add_user(@group_owner, GroupMember::OWNER) @group.add_user(@group_owner, GroupMember::OWNER)
@group.add_user(@developer, GroupMember::DEVELOPER) @group.add_user(@developer, GroupMember::DEVELOPER)
@project.add_user(@developer, :developer)
@project.add_user(@group_owner, :developer)
@opts = { namespace: @group } @opts = { namespace: @group }
end end
context 'fork project for group' do context 'fork project for group' do
it 'group owner successfully forks project into the group' do it 'group owner successfully forks project into the group' do
to_project = fork_project(@project, @group_owner, @opts) to_project = fork_project(@project, @group_owner, @opts)
expect(to_project).to be_persisted
expect(to_project.errors).to be_empty
expect(to_project.owner).to eq(@group) expect(to_project.owner).to eq(@group)
expect(to_project.namespace).to eq(@group) expect(to_project.namespace).to eq(@group)
expect(to_project.name).to eq(@project.name) expect(to_project.name).to eq(@project.name)
expect(to_project.path).to eq(@project.path) expect(to_project.path).to eq(@project.path)
expect(to_project.description).to eq(@project.description) expect(to_project.description).to eq(@project.description)
expect(to_project.star_count).to be_zero expect(to_project.star_count).to be_zero
end end
end end
......
...@@ -451,7 +451,7 @@ describe SystemNoteService, services: true do ...@@ -451,7 +451,7 @@ describe SystemNoteService, services: true do
end end
context 'commit with cross-reference from fork' do context 'commit with cross-reference from fork' do
let(:author2) { create(:user) } let(:author2) { create(:project_member, :reporter, user: create(:user), project: project).user }
let(:forked_project) { Projects::ForkService.new(project, author2).execute } let(:forked_project) { Projects::ForkService.new(project, author2).execute }
let(:commit2) { forked_project.commit } let(:commit2) { forked_project.commit }
......
...@@ -130,4 +130,8 @@ module ExportFileHelper ...@@ -130,4 +130,8 @@ module ExportFileHelper
(parsed_model_attributes - parent.keys - excluded_attributes).empty? (parsed_model_attributes - parent.keys - excluded_attributes).empty?
end end
def file_permissions(file)
File.stat(file).mode & 0777
end
end end
require 'spec_helper' require 'spec_helper'
describe 'ci/lints/show' do describe 'ci/lints/show' do
include Devise::TestHelpers
describe 'XSS protection' do
let(:config_processor) { Ci::GitlabCiYamlProcessor.new(YAML.dump(content)) }
before do
assign(:status, true)
assign(:builds, config_processor.builds)
assign(:stages, config_processor.stages)
assign(:jobs, config_processor.jobs)
end
context 'when builds attrbiutes contain HTML nodes' do
let(:content) do
{
rspec: {
script: '<h1>rspec</h1>',
stage: 'test'
}
}
end
it 'does not render HTML elements' do
render
expect(rendered).not_to have_css('h1', text: 'rspec')
end
end
context 'when builds attributes do not contain HTML nodes' do
let(:content) do
{
rspec: {
script: 'rspec',
stage: 'test'
}
}
end
it 'shows configuration in the table' do
render
expect(rendered).to have_css('td pre', text: 'rspec')
end
end
end
let(:content) do let(:content) do
{ {
build_template: { build_template: {
......
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