Commit 3ffd40ae authored by Marin Jankovski's avatar Marin Jankovski

Merge branch 'ce-to-ee-2018-02-23' into 'master'

CE upstream - 2018-02-23 12:10 UTC

See merge request gitlab-org/gitlab-ee!4692
parents abd17639 f382321f
......@@ -418,6 +418,16 @@ export const convertObjectPropsToCamelCase = (obj = {}) => {
export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`;
export const addSelectOnFocusBehaviour = (selector = '.js-select-on-focus') => {
// Click a .js-select-on-focus field, select the contents
// Prevent a mouseup event from deselecting the input
$(selector).on('focusin', function selectOnFocusCallback() {
$(this).select().one('mouseup', (e) => {
e.preventDefault();
});
});
};
window.gl = window.gl || {};
window.gl.utils = {
...(window.gl.utils || {}),
......
......@@ -10,7 +10,7 @@ window.jQuery = jQuery;
window.$ = jQuery;
// lib/utils
import { handleLocationHash } from './lib/utils/common_utils';
import { handleLocationHash, addSelectOnFocusBehaviour } from './lib/utils/common_utils';
import { localTimeAgo } from './lib/utils/datetime_utility';
import { getLocationHash, visitUrl } from './lib/utils/url_utility';
......@@ -107,13 +107,7 @@ document.addEventListener('DOMContentLoaded', () => {
return true;
});
// Click a .js-select-on-focus field, select the contents
// Prevent a mouseup event from deselecting the input
$('.js-select-on-focus').on('focusin', function selectOnFocusCallback() {
$(this).select().one('mouseup', (e) => {
e.preventDefault();
});
});
addSelectOnFocusBehaviour('.js-select-on-focus');
$('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() {
$(this).tooltip('destroy')
......
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
let hasUserDefinedProjectPath = false;
const deriveProjectPathFromUrl = ($projectImportUrl) => {
......@@ -36,6 +38,7 @@ const bindEvents = () => {
const $changeTemplateBtn = $('.change-template');
const $selectedIcon = $('.selected-icon svg');
const $templateProjectNameInput = $('#template-project-name #project_path');
const $pushNewProjectTipTrigger = $('.push-new-project-tip');
if ($newProjectForm.length !== 1) {
return;
......@@ -55,6 +58,34 @@ const bindEvents = () => {
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`);
});
if ($pushNewProjectTipTrigger) {
$pushNewProjectTipTrigger
.removeAttr('rel')
.removeAttr('target')
.on('click', (e) => { e.preventDefault(); })
.popover({
title: $pushNewProjectTipTrigger.data('title'),
placement: 'auto bottom',
html: 'true',
content: $('.push-new-project-tip-template').html(),
})
.on('shown.bs.popover', () => {
$(document).on('click.popover touchstart.popover', (event) => {
if ($(event.target).closest('.popover').length === 0) {
$pushNewProjectTipTrigger.trigger('click');
}
});
const target = $(`#${$pushNewProjectTipTrigger.attr('aria-describedby')}`).find('.js-select-on-focus');
addSelectOnFocusBehaviour(target);
target.focus();
})
.on('hide.bs.popover', () => {
$(document).off('click.popover touchstart.popover');
});
}
function chooseTemplate() {
$('.template-option').hide();
$projectFieldsForm.addClass('selected');
......
......@@ -333,6 +333,10 @@ a > code {
font-family: $monospace_font;
}
.weight-normal {
font-weight: $gl-font-weight-normal;
}
.commit-sha,
.ref-name {
@extend .monospace;
......
......@@ -908,6 +908,12 @@ a.allowed-to-push {
}
}
.project-tip-command {
> .input-group-btn:first-child {
width: auto;
}
}
.protected-branches-list,
.protected-tags-list {
margin-bottom: 30px;
......
class Groups::ApplicationController < ApplicationController
include RoutableActions
prepend EE::Groups::ApplicationController
include RoutableActions
include ControllerWithCrossProjectAccessCheck
layout 'group'
......
......@@ -9,6 +9,10 @@ class Groups::GroupMembersController < Groups::ApplicationController
before_action :authorize_admin_group_member!, except: [:index, :leave, :request_access, :update, :override]
before_action :authorize_update_group_member!, only: [:update, :override]
skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite,
:override
skip_cross_project_access_check :index, :create, :update, :destroy, :request_access,
:approve_access_request, :leave, :resend_invite,
:override
......
......@@ -47,7 +47,7 @@ class ProjectsController < Projects::ApplicationController
notice: _("Project '%{project_name}' was successfully created.") % { project_name: @project.name }
)
else
render 'new'
render 'new', locals: { active_tab: ('import' if project_params[:import_url].present?) }
end
end
......
......@@ -263,6 +263,17 @@ module ProjectsHelper
!!(params[:personal] || params[:name] || any_projects?(projects))
end
def push_to_create_project_command(user = current_user)
repository_url =
if Gitlab::CurrentSettings.current_application_settings.enabled_git_access_protocol == 'http'
user_url(user)
else
Gitlab.config.gitlab_shell.ssh_path_prefix + user.username
end
"git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)"
end
private
def repo_children_classes(field)
......
......@@ -2,6 +2,7 @@
- merge_requests_count = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute.count
- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index']
- if @group.feature_available?(:group_issue_boards)
- issues_sub_menu_items.push('boards#index', 'boards#show')
......
.push-to-create-popover
%p
= label_tag(:push_to_create_tip, _("Private projects can be created in your personal namespace with:"), class: "weight-normal")
%p.input-group.project-tip-command
%span.input-group-btn
= text_field_tag :push_to_create_tip, push_to_create_project_command, class: "js-select-on-focus form-control monospace", readonly: true, aria: { label: _("Push project from command line") }
%span.input-group-btn
= clipboard_button(text: push_to_create_project_command, title: _("Copy command to clipboard"), placement: "right")
%p
= link_to("What does this command do?", help_page_path("gitlab-basics/create-project", anchor: "push-to-create-a-new-project"), target: "_blank")
......@@ -4,6 +4,7 @@
- page_title 'New Project'
- header_title "Projects", dashboard_projects_path
- visibility_level = params.dig(:project, :visibility_level) || default_project_visibility
- active_tab = local_assigns.fetch(:active_tab, 'blank')
.project-edit-container
.project-edit-errors
......@@ -18,34 +19,41 @@
All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings.
.md
= brand_new_project_guidelines
%p
%strong= _("Tip:")
= _("You can also create a project from the command line.")
%a.push-new-project-tip{ data: { title: _("Push to create a project") }, href: help_page_path('gitlab-basics/create-project', anchor: 'push-to-create-a-new-project'), target: "_blank", rel: "noopener noreferrer" }
= _("Show command")
%template.push-new-project-tip-template= render partial: "new_project_push_tip"
.col-lg-9.js-toggle-container
%ul.nav-links.gitlab-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' }
%li{ class: ('active' if active_tab == 'blank'), role: 'presentation' }
%a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Blank project
%span.visible-xs Blank
%li{ role: 'presentation' }
%li{ class: ('active' if active_tab == 'template'), role: 'presentation' }
%a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Create from template
%span.visible-xs Template
%li{ role: 'presentation' }
%li{ class: ('active' if active_tab == 'import'), role: 'presentation' }
%a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.hidden-xs Import project
%span.visible-xs Import
.tab-content.gitlab-tab-content
.tab-pane.active{ id: 'blank-project-pane', role: 'tabpanel' }
.tab-pane{ id: 'blank-project-pane', class: ('active' if active_tab == 'blank'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
= render 'new_project_fields', f: f, project_name_id: "blank-project-name"
.tab-pane.no-padding{ id: 'create-from-template-pane', role: 'tabpanel' }
.tab-pane.no-padding{ id: 'create-from-template-pane', class: ('active' if active_tab == 'template'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
.project-template
.form-group
%div
= render 'project_templates', f: f
.tab-pane.import-project-pane{ id: 'import-project-pane', role: 'tabpanel' }
.tab-pane.import-project-pane{ id: 'import-project-pane', class: ('active' if active_tab == 'import'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
- if import_sources_enabled?
.project-import.row
......@@ -92,7 +100,7 @@
%button.btn.js-toggle-button.import_git{ type: "button" }
= icon('git', text: 'Repo by URL')
.col-lg-12
.js-toggle-content.hide.toggle-import-form
.js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') }
%hr
= render "shared/import_form", f: f
= render 'new_project_fields', f: f, project_name_id: "import-url-name"
......
---
title: Keep "Import project" tab/form active when validation fails trying to import
"Repo by URL"
merge_request: 17136
author:
type: fixed
---
title: Allow token authentication on go-get request
merge_request:
author:
type: changed
......@@ -47,10 +47,10 @@ This can be done by using either SSH or HTTP:
```
## Git push using SSH
git push git@gitlab.example.com:namespace/nonexistent-project.git
git push --set-upstream git@gitlab.example.com:namespace/nonexistent-project.git master
## Git push using HTTP
git push https://gitlab.example.com/namespace/nonexistent-project.git
git push --set-upstream https://gitlab.example.com/namespace/nonexistent-project.git master
```
Once the push finishes successfully, a remote message will indicate
......
......@@ -19,8 +19,9 @@ module Banzai
#
# Returns the documents passed as the first argument.
def redact(documents)
all_document_nodes = document_nodes(documents)
redact_cross_project_references(documents) unless can_read_cross_project?
all_document_nodes = document_nodes(documents)
redact_document_nodes(all_document_nodes)
end
......@@ -51,6 +52,18 @@ module Banzai
metadata
end
def redact_cross_project_references(documents)
extractor = Banzai::IssuableExtractor.new(project, user)
issuables = extractor.extract(documents)
issuables.each do |node, issuable|
next if issuable.project == project
node['class'] = node['class'].gsub('has-tooltip', '')
node['title'] = nil
end
end
# Returns the nodes visible to the current user.
#
# nodes - The input nodes to check.
......@@ -78,5 +91,11 @@ module Banzai
{ document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') }
end
end
private
def can_read_cross_project?
Ability.allowed?(user, :read_cross_project)
end
end
end
......@@ -20,6 +20,14 @@ module Gitlab
rescue Gitlab::Auth::AuthenticationError
nil
end
def valid_access_token?(scopes: [])
validate_access_token!(scopes: scopes)
true
rescue Gitlab::Auth::AuthenticationError
false
end
end
end
end
......@@ -114,7 +114,15 @@ module Gitlab
end
def current_user(request)
request.env['warden']&.authenticate
authenticator = Gitlab::Auth::RequestAuthenticator.new(request)
user = authenticator.find_user_from_access_token || authenticator.find_user_from_warden
return unless user&.can?(:access_api)
# Right now, the `api` scope is the only one that should be able to determine private project existence.
return unless authenticator.valid_access_token?(scopes: [:api])
user
end
end
end
......
......@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-02-22 17:55+0100\n"
"PO-Revision-Date: 2018-02-22 17:55+0100\n"
"POT-Creation-Date: 2018-02-23 13:23+0100\n"
"PO-Revision-Date: 2018-02-23 13:23+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -135,9 +135,15 @@ msgstr ""
msgid "Add Group Webhooks and GitLab Enterprise Edition."
msgstr ""
msgid "Add Kubernetes cluster"
msgstr ""
msgid "Add License"
msgstr ""
msgid "Add Readme"
msgstr ""
msgid "Add new directory"
msgstr ""
......@@ -354,6 +360,9 @@ msgstr ""
msgid "Authors: %{authors}"
msgstr ""
msgid "Auto DevOps enabled"
msgstr ""
msgid "Auto Review Apps and Auto Deploy need a %{kubernetes} to work correctly."
msgstr ""
......@@ -378,7 +387,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
msgid "AutoDevOps|You can activate %{link_to_settings} for this project."
msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
msgstr ""
msgid "AutoDevOps|add a Kubernetes cluster"
msgstr ""
msgid "AutoDevOps|enable Auto DevOps (Beta)"
msgstr ""
msgid "Available"
......@@ -447,8 +462,8 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
msgid "Branch"
msgid_plural "Branches"
msgid "Branch (%{branch_count})"
msgid_plural "Branches (%{branch_count})"
msgstr[0] ""
msgstr[1] ""
......@@ -1042,6 +1057,11 @@ msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
msgid "Commit (%{commit_count})"
msgid_plural "Commits (%{commit_count})"
msgstr[0] ""
msgstr[1] ""
msgid "Commit Message"
msgstr ""
......@@ -1195,6 +1215,9 @@ msgstr ""
msgid "Copy branch name to clipboard"
msgstr ""
msgid "Copy command to clipboard"
msgstr ""
msgid "Copy commit SHA to clipboard"
msgstr ""
......@@ -1404,6 +1427,9 @@ msgstr ""
msgid "Enable"
msgstr ""
msgid "Enable Auto DevOps"
msgstr ""
msgid "Environments|An error occurred while fetching the environments."
msgstr ""
......@@ -1575,6 +1601,9 @@ msgstr ""
msgid "Files"
msgstr ""
msgid "Files (%{human_size})"
msgstr ""
msgid "Filter by commit message"
msgstr ""
......@@ -1873,6 +1902,9 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr ""
msgid "If you already have files you can push them using the %{link_to_cli} below."
msgstr ""
msgid "Import repository"
msgstr ""
......@@ -1968,6 +2000,9 @@ msgstr ""
msgid "Kubernetes cluster was successfully updated."
msgstr ""
msgid "Kubernetes configured"
msgstr ""
msgid "Kubernetes service integration has been deprecated. %{deprecated_message_content} your Kubernetes clusters using the new <a href=\"%{url}\"/>Kubernetes Clusters</a> page"
msgstr ""
......@@ -2015,6 +2050,9 @@ msgstr ""
msgid "Learn more"
msgstr ""
msgid "Learn more about protected branches"
msgstr ""
msgid "Learn more in the"
msgstr ""
......@@ -2251,6 +2289,9 @@ msgstr ""
msgid "Not enough data"
msgstr ""
msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
msgstr ""
msgid "Notification events"
msgstr ""
......@@ -2353,6 +2394,9 @@ msgstr ""
msgid "Options"
msgstr ""
msgid "Otherwise it is recommended you start with one of the options below."
msgstr ""
msgid "Overview"
msgstr ""
......@@ -2461,19 +2505,19 @@ msgstr ""
msgid "Pipeline|Retry pipeline"
msgstr ""
msgid "Pipeline|Retry pipeline #%{id}?"
msgid "Pipeline|Retry pipeline #%{pipelineId}?"
msgstr ""
msgid "Pipeline|Stop pipeline"
msgstr ""
msgid "Pipeline|Stop pipeline #%{id}?"
msgid "Pipeline|Stop pipeline #%{pipelineId}?"
msgstr ""
msgid "Pipeline|You’re about to retry pipeline %{id}."
msgid "Pipeline|You’re about to retry pipeline %{pipelineId}."
msgstr ""
msgid "Pipeline|You’re about to stop pipeline %{id}."
msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
msgstr ""
msgid "Pipeline|all"
......@@ -2509,6 +2553,9 @@ msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
msgid "Private projects can be created in your personal namespace with:"
msgstr ""
msgid "Profile"
msgstr ""
......@@ -2746,6 +2793,12 @@ msgstr ""
msgid "Push events"
msgstr ""
msgid "Push project from command line"
msgstr ""
msgid "Push to create a project"
msgstr ""
msgid "PushRule|Committer restriction"
msgstr ""
......@@ -2928,9 +2981,6 @@ msgstr ""
msgid "Set up Koding"
msgstr ""
msgid "Set up auto deploy"
msgstr ""
msgid "SetPasswordToCloneLink|set a password"
msgstr ""
......@@ -2946,6 +2996,9 @@ msgstr ""
msgid "SharedRunnersMinutesSettings|Reset used pipeline minutes"
msgstr ""
msgid "Show command"
msgstr ""
msgid "Show parent pages"
msgstr ""
......@@ -3149,8 +3202,8 @@ msgstr ""
msgid "System Hooks"
msgstr ""
msgid "Tag"
msgid_plural "Tags"
msgid "Tag (%{tag_count})"
msgid_plural "Tags (%{tag_count})"
msgstr[0] ""
msgstr[1] ""
......@@ -3283,6 +3336,9 @@ msgstr ""
msgid "The repository for this project does not exist."
msgstr ""
msgid "The repository for this project is empty"
msgstr ""
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
......@@ -3554,6 +3610,9 @@ msgstr[1] ""
msgid "Time|s"
msgstr ""
msgid "Tip:"
msgstr ""
msgid "Title"
msgstr ""
......@@ -3827,6 +3886,9 @@ msgstr ""
msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You can also create a project from the command line."
msgstr ""
msgid "You can also star a label to make it a priority label."
msgstr ""
......@@ -3974,6 +4036,9 @@ msgstr ""
msgid "ciReport|no security vulnerabilities"
msgstr ""
msgid "command line instructions"
msgstr ""
msgid "commit"
msgstr ""
......
......@@ -140,7 +140,7 @@ feature 'New project' do
find('#import-project-tab').click
end
context 'from git repository url' do
context 'from git repository url, "Repo by URL"' do
before do
first('.import_git').click
end
......@@ -157,6 +157,18 @@ feature 'New project' do
expect(git_import_instructions).to be_visible
expect(git_import_instructions).to have_content 'Git repository URL'
end
it 'keeps "Import project" tab open after form validation error' do
collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace)
fill_in 'project_import_url', with: collision_project.http_url_to_repo
fill_in 'project_path', with: collision_project.path
click_on 'Create project'
expect(page).to have_css('#import-project-pane.active')
expect(page).not_to have_css('.toggle-import-form.hide')
end
end
context 'from GitHub' do
......
......@@ -25,6 +25,24 @@ feature 'Project' do
end
end
describe 'shows tip about push to create git command' do
let(:user) { create(:user) }
before do
sign_in user
visit new_project_path
end
it 'shows the command in a popover', :js do
page.within '.profile-settings-sidebar' do
click_link 'Show command'
end
expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip')
expect(page).to have_content 'Private projects can be created in your personal namespace with:'
end
end
describe 'description' do
let(:project) { create(:project, :repository) }
let(:path) { project_path(project) }
......
......@@ -178,9 +178,27 @@ describe SnippetsFinder do
end
end
describe "#execute" do
# Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb
include_examples 'snippet visibility', described_class
describe '#execute' do
let(:project) { create(:project, :public) }
let!(:project_snippet) { create(:project_snippet, :public, project: project) }
let!(:personal_snippet) { create(:personal_snippet, :public) }
let(:user) { create(:user) }
subject(:finder) { described_class.new(user) }
it 'returns project- and personal snippets' do
expect(finder.execute).to contain_exactly(project_snippet, personal_snippet)
end
context 'when the user cannot read cross project' do
before do
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
end
it 'returns only personal snippets when the user cannot read cross project' do
expect(finder.execute).to contain_exactly(personal_snippet)
end
end
end
describe '#execute' do
......
......@@ -455,6 +455,22 @@ describe ProjectsHelper do
end
end
describe('#push_to_create_project_command') do
let(:user) { create(:user, username: 'john') }
it 'returns the command to push to create project over HTTP' do
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'http' }
expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream http://test.host/john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)')
end
it 'returns the command to push to create project over SSH' do
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'ssh' }
expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream git@localhost:john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)')
end
end
describe '#any_projects?' do
let!(:project) { create(:project) }
......
......@@ -6,7 +6,7 @@ describe Banzai::Filter::RedactorFilter do
it 'ignores non-GFM links' do
html = %(See <a href="https://google.com/">Google</a>)
doc = filter(html, current_user: double)
doc = filter(html, current_user: build(:user))
expect(doc.css('a').length).to eq 1
end
......
......@@ -88,6 +88,55 @@ describe Banzai::Redactor do
end
end
context 'when the user cannot read cross project' do
include ActionView::Helpers::UrlHelper
let(:project) { create(:project) }
let(:other_project) { create(:project, :public) }
def create_link(issuable)
type = issuable.class.name.underscore.downcase
link_to(issuable.to_reference, '',
class: 'gfm has-tooltip',
title: issuable.title,
data: {
reference_type: type,
"#{type}": issuable.id
})
end
before do
project.add_developer(user)
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?).with(user, :read_cross_project, :global) { false }
allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false }
end
it 'skips links to issues within the same project' do
issue = create(:issue, project: project)
link = create_link(issue)
doc = Nokogiri::HTML.fragment(link)
redactor.redact([doc])
result = doc.css('a').last
expect(result['class']).to include('has-tooltip')
expect(result['title']).to eq(issue.title)
end
it 'removes info from a cross project reference' do
issue = create(:issue, project: other_project)
link = create_link(issue)
doc = Nokogiri::HTML.fragment(link)
redactor.redact([doc])
result = doc.css('a').last
expect(result['class']).not_to include('has-tooltip')
expect(result['title']).to be_empty
end
end
describe '#redact_nodes' do
it 'redacts an Array of nodes' do
doc = Nokogiri::HTML.fragment('<a href="foo">foo</a>')
......
......@@ -3,19 +3,30 @@ require 'spec_helper'
describe Gitlab::Middleware::Go do
let(:app) { double(:app) }
let(:middleware) { described_class.new(app) }
let(:env) do
{
'rack.input' => '',
'REQUEST_METHOD' => 'GET'
}
end
describe '#call' do
describe 'when go-get=0' do
before do
env['QUERY_STRING'] = 'go-get=0'
end
it 'skips go-import generation' do
env = { 'rack.input' => '',
'QUERY_STRING' => 'go-get=0' }
expect(app).to receive(:call).with(env).and_return('no-go')
middleware.call(env)
end
end
describe 'when go-get=1' do
let(:current_user) { nil }
before do
env['QUERY_STRING'] = 'go-get=1'
env['PATH_INFO'] = "/#{path}"
end
shared_examples 'go-get=1' do |enabled_protocol:|
context 'with simple 2-segment project path' do
......@@ -54,21 +65,75 @@ describe Gitlab::Middleware::Go do
project.update_attribute(:visibility_level, Project::PRIVATE)
end
context 'with access to the project' do
shared_examples 'unauthorized' do
it 'returns the 2-segment group path' do
expect_response_with_path(go, enabled_protocol, group.full_path)
end
end
context 'when not authenticated' do
it_behaves_like 'unauthorized'
end
context 'when authenticated' do
let(:current_user) { project.creator }
before do
project.team.add_master(current_user)
end
shared_examples 'authenticated' do
context 'with access to the project' do
it 'returns the full project path' do
expect_response_with_path(go, enabled_protocol, project.full_path)
end
end
context 'without access to the project' do
it 'returns the 2-segment group path' do
expect_response_with_path(go, enabled_protocol, group.full_path)
before do
project.team.find_member(current_user).destroy
end
it_behaves_like 'unauthorized'
end
end
context 'using warden' do
before do
env['warden'] = double(authenticate: current_user)
end
context 'when active' do
it_behaves_like 'authenticated'
end
context 'when blocked' do
before do
current_user.block!
end
it_behaves_like 'unauthorized'
end
end
context 'using a personal access token' do
let(:personal_access_token) { create(:personal_access_token, user: current_user) }
before do
env['HTTP_PRIVATE_TOKEN'] = personal_access_token.token
end
context 'with api scope' do
it_behaves_like 'authenticated'
end
context 'with read_user scope' do
before do
personal_access_token.update_attribute(:scopes, [:read_user])
end
it_behaves_like 'unauthorized'
end
end
end
end
......@@ -138,12 +203,6 @@ describe Gitlab::Middleware::Go do
end
def go
env = {
'rack.input' => '',
'QUERY_STRING' => 'go-get=1',
'PATH_INFO' => "/#{path}",
'warden' => double(authenticate: current_user)
}
middleware.call(env)
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