Commit 490aacf5 authored by Stan Hu's avatar Stan Hu

Merge branch 'rs-pick-security' into 'master'

Pick 10.4.3 fixes into master

See merge request gitlab-org/gitlab-ce!17040
parents 721fab66 56a41ceb
...@@ -30,6 +30,9 @@ export default function renderMermaid($els) { ...@@ -30,6 +30,9 @@ export default function renderMermaid($els) {
$els.each((i, el) => { $els.each((i, el) => {
const source = el.textContent; const source = el.textContent;
// Remove any extra spans added by the backend syntax highlighting.
Object.assign(el, { textContent: source });
mermaid.init(undefined, el, (id) => { mermaid.init(undefined, el, (id) => {
const svg = document.getElementById(id); const svg = document.getElementById(id);
......
...@@ -2,26 +2,16 @@ class Import::BaseController < ApplicationController ...@@ -2,26 +2,16 @@ class Import::BaseController < ApplicationController
private private
def find_or_create_namespace(names, owner) def find_or_create_namespace(names, owner)
return current_user.namespace if names == owner
return current_user.namespace unless current_user.can_create_group?
names = params[:target_namespace].presence || names names = params[:target_namespace].presence || names
full_path_namespace = Namespace.find_by_full_path(names)
return full_path_namespace if full_path_namespace return current_user.namespace if names == owner
group = Groups::NestedCreateService.new(current_user, group_path: names).execute
names.split('/').inject(nil) do |parent, name| group.errors.any? ? current_user.namespace : group
begin rescue => e
namespace = Group.create!(name: name, Gitlab::AppLogger.error(e)
path: name,
owner: current_user,
parent: parent)
namespace.add_owner(current_user)
namespace current_user.namespace
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
Namespace.where(parent: parent).find_by_path_or_name(name)
end
end
end end
end end
# Snippets Finder
#
# Used to filter Snippets collections by a set of params
#
# Arguments.
#
# current_user - The current user, nil also can be used.
# params:
# visibility (integer) - Individual snippet visibility: Public(20), internal(10) or private(0).
# project (Project) - Project related.
# author (User) - Author related.
#
# params are optional
class SnippetsFinder < UnionFinder class SnippetsFinder < UnionFinder
attr_accessor :current_user, :params include Gitlab::Allowable
attr_accessor :current_user, :params, :project
def initialize(current_user, params = {}) def initialize(current_user, params = {})
@current_user = current_user @current_user = current_user
@params = params @params = params
@project = params[:project]
end end
def execute def execute
items = init_collection items = init_collection
items = by_project(items)
items = by_author(items) items = by_author(items)
items = by_visibility(items) items = by_visibility(items)
...@@ -18,25 +32,42 @@ class SnippetsFinder < UnionFinder ...@@ -18,25 +32,42 @@ class SnippetsFinder < UnionFinder
private private
def init_collection def init_collection
items = Snippet.all if project.present?
authorized_snippets_from_project
else
authorized_snippets
end
end
accessible(items) def authorized_snippets_from_project
if can?(current_user, :read_project_snippet, project)
if project.team.member?(current_user)
project.snippets
else
project.snippets.public_to_user(current_user)
end
else
Snippet.none
end
end end
def accessible(items) def authorized_snippets
segments = [] Snippet.where(feature_available_projects.or(not_project_related)).public_or_visible_to_user(current_user)
segments << items.public_to_user(current_user) end
segments << authorized_to_user(items) if current_user
find_union(segments, Snippet.includes(:author)) def feature_available_projects
projects = Project.public_or_visible_to_user(current_user)
.with_feature_available_for_user(:snippets, current_user).select(:id)
arel_query = Arel::Nodes::SqlLiteral.new(projects.to_sql)
table[:project_id].in(arel_query)
end end
def authorized_to_user(items) def not_project_related
items.where( table[:project_id].eq(nil)
'author_id = :author_id end
OR project_id IN (:project_ids)',
author_id: current_user.id, def table
project_ids: current_user.authorized_projects.select(:id)) Snippet.arel_table
end end
def by_visibility(items) def by_visibility(items)
...@@ -53,12 +84,6 @@ class SnippetsFinder < UnionFinder ...@@ -53,12 +84,6 @@ class SnippetsFinder < UnionFinder
items.where(author_id: params[:author].id) items.where(author_id: params[:author].id)
end end
def by_project(items)
return items unless params[:project]
items.where(project_id: params[:project].id)
end
def visibility_from_scope def visibility_from_scope
case params[:scope].to_s case params[:scope].to_s
when 'are_private' when 'are_private'
......
...@@ -1589,8 +1589,11 @@ class Project < ActiveRecord::Base ...@@ -1589,8 +1589,11 @@ class Project < ActiveRecord::Base
end end
def protected_for?(ref) def protected_for?(ref)
ProtectedBranch.protected?(self, ref) || if repository.branch_exists?(ref)
ProtectedBranch.protected?(self, ref)
elsif repository.tag_exists?(ref)
ProtectedTag.protected?(self, ref) ProtectedTag.protected?(self, ref)
end
end end
def deployment_variables def deployment_variables
......
...@@ -74,6 +74,27 @@ class Snippet < ActiveRecord::Base ...@@ -74,6 +74,27 @@ class Snippet < ActiveRecord::Base
@link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/) @link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/)
end end
# Returns a collection of snippets that are either public or visible to the
# logged in user.
#
# This method does not verify the user actually has the access to the project
# the snippet is in, so it should be only used on a relation that's already scoped
# for project access
def self.public_or_visible_to_user(user = nil)
if user
authorized = user
.project_authorizations
.select(1)
.where('project_authorizations.project_id = snippets.project_id')
levels = Gitlab::VisibilityLevel.levels_for_user(user)
where('EXISTS (?) OR snippets.visibility_level IN (?) or snippets.author_id = (?)', authorized, levels, user.id)
else
public_to_user
end
end
def to_reference(from = nil, full: false) def to_reference(from = nil, full: false)
reference = "#{self.class.reference_prefix}#{id}" reference = "#{self.class.reference_prefix}#{id}"
......
...@@ -119,7 +119,6 @@ class ProjectPolicy < BasePolicy ...@@ -119,7 +119,6 @@ class ProjectPolicy < BasePolicy
enable :create_note enable :create_note
enable :upload_file enable :upload_file
enable :read_cycle_analytics enable :read_cycle_analytics
enable :read_project_snippet
end end
rule { can?(:reporter_access) }.policy do rule { can?(:reporter_access) }.policy do
......
...@@ -11,8 +11,8 @@ module Groups ...@@ -11,8 +11,8 @@ module Groups
def execute def execute
return nil unless group_path return nil unless group_path
if group = Group.find_by_full_path(group_path) if namespace = namespace_or_group(group_path)
return group return namespace
end end
if group_path.include?('/') && !Group.supports_nested_groups? if group_path.include?('/') && !Group.supports_nested_groups?
...@@ -40,10 +40,14 @@ module Groups ...@@ -40,10 +40,14 @@ module Groups
) )
new_params[:visibility_level] ||= Gitlab::CurrentSettings.current_application_settings.default_group_visibility new_params[:visibility_level] ||= Gitlab::CurrentSettings.current_application_settings.default_group_visibility
last_group = Group.find_by_full_path(partial_path) || Groups::CreateService.new(current_user, new_params).execute last_group = namespace_or_group(partial_path) || Groups::CreateService.new(current_user, new_params).execute
end end
last_group last_group
end end
def namespace_or_group(group_path)
Namespace.find_by_full_path(group_path)
end
end end
end end
...@@ -60,7 +60,7 @@ module API ...@@ -60,7 +60,7 @@ module API
end end
post ':id/mark_as_done' do post ':id/mark_as_done' do
TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user) TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user)
todo = Todo.find(params[:id]) todo = current_user.todos.find(params[:id])
present todo, with: Entities::Todo, current_user: current_user present todo, with: Entities::Todo, current_user: current_user
end end
......
...@@ -12,7 +12,7 @@ module API ...@@ -12,7 +12,7 @@ module API
end end
delete ':id' do delete ':id' do
TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user) TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user)
todo = Todo.find(params[:id]) todo = current_user.todos.find(params[:id])
present todo, with: ::API::Entities::Todo, current_user: current_user present todo, with: ::API::Entities::Todo, current_user: current_user
end end
......
...@@ -14,23 +14,33 @@ module Banzai ...@@ -14,23 +14,33 @@ module Banzai
end end
def highlight_node(node) def highlight_node(node)
code = node.text
css_classes = 'code highlight js-syntax-highlight' css_classes = 'code highlight js-syntax-highlight'
language = node.attr('lang') lang = node.attr('lang')
retried = false
if use_rouge?(language) if use_rouge?(lang)
lexer = lexer_for(language) lexer = lexer_for(lang)
language = lexer.tag language = lexer.tag
else
lexer = Rouge::Lexers::PlainText.new
language = lang
end
begin
code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, node.text), tag: language)
css_classes << " #{language}" if language
rescue
# Gracefully handle syntax highlighter bugs/errors to ensure users can
# still access an issue/comment/etc. First, retry with the plain text
# filter. If that fails, then just skip this entirely, but that would
# be a pretty bad upstream bug.
return if retried
begin language = nil
code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, code), tag: language) lexer = Rouge::Lexers::PlainText.new
css_classes << " #{language}" retried = true
rescue
# Gracefully handle syntax highlighter bugs/errors to ensure
# users can still access an issue/comment/etc.
language = nil retry
end
end end
highlighted = %(<pre class="#{css_classes}" lang="#{language}" v-pre="true"><code>#{code}</code></pre>) highlighted = %(<pre class="#{css_classes}" lang="#{language}" v-pre="true"><code>#{code}</code></pre>)
......
...@@ -222,7 +222,7 @@ describe Import::BitbucketController do ...@@ -222,7 +222,7 @@ describe Import::BitbucketController do
end end
end end
context 'user has chosen an existing nested namespace and name for the project' do context 'user has chosen an existing nested namespace and name for the project', :postgresql do
let(:parent_namespace) { create(:group, name: 'foo', owner: user) } let(:parent_namespace) { create(:group, name: 'foo', owner: user) }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
...@@ -240,7 +240,7 @@ describe Import::BitbucketController do ...@@ -240,7 +240,7 @@ describe Import::BitbucketController do
end end
end end
context 'user has chosen a non-existent nested namespaces and name for the project' do context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do it 'takes the selected namespace and name' do
...@@ -271,10 +271,14 @@ describe Import::BitbucketController do ...@@ -271,10 +271,14 @@ describe Import::BitbucketController do
end end
end end
context 'user has chosen existent and non-existent nested namespaces and name for the project' do context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo', owner: user) } let!(:parent_namespace) { create(:group, name: 'foo', owner: user) }
before do
parent_namespace.add_owner(user)
end
it 'takes the selected namespace and name' do it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator) expect(Gitlab::BitbucketImport::ProjectCreator)
.to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params) .to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params)
......
...@@ -195,7 +195,7 @@ describe Import::GitlabController do ...@@ -195,7 +195,7 @@ describe Import::GitlabController do
end end
end end
context 'user has chosen an existing nested namespace for the project' do context 'user has chosen an existing nested namespace for the project', :postgresql do
let(:parent_namespace) { create(:group, name: 'foo', owner: user) } let(:parent_namespace) { create(:group, name: 'foo', owner: user) }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
...@@ -212,7 +212,7 @@ describe Import::GitlabController do ...@@ -212,7 +212,7 @@ describe Import::GitlabController do
end end
end end
context 'user has chosen a non-existent nested namespaces for the project' do context 'user has chosen a non-existent nested namespaces for the project', :postgresql do
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do it 'takes the selected namespace and name' do
...@@ -243,10 +243,14 @@ describe Import::GitlabController do ...@@ -243,10 +243,14 @@ describe Import::GitlabController do
end end
end end
context 'user has chosen existent and non-existent nested namespaces and name for the project' do context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo', owner: user) } let!(:parent_namespace) { create(:group, name: 'foo', owner: user) }
before do
parent_namespace.add_owner(user)
end
it 'takes the selected namespace and name' do it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator) expect(Gitlab::GitlabImport::ProjectCreator)
.to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params) .to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params)
......
require 'spec_helper'
describe 'Math rendering', :js do
it 'renders inline and display math correctly' do
description = <<~MATH
This math is inline $`a^2+b^2=c^2`$.
This is on a separate line
```math
a^2+b^2=c^2
```
MATH
project = create(:project, :public)
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
expect(page).to have_selector('.katex .mord.mathit', text: 'b')
expect(page).to have_selector('.katex-display .mord.mathit', text: 'b')
end
end
require 'spec_helper'
describe 'Mermaid rendering', :js do
it 'renders Mermaid diagrams correctly' do
description = <<~MERMAID
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
MERMAID
project = create(:project, :public)
issue = create(:issue, project: project, description: description)
visit project_issue_path(project, issue)
%w[A B C D].each do |label|
expect(page).to have_selector('svg foreignObject', text: label)
end
end
end
require 'spec_helper' require 'spec_helper'
describe SnippetsFinder do describe SnippetsFinder do
let(:user) { create :user } include Gitlab::Allowable
let(:user1) { create :user } using RSpec::Parameterized::TableSyntax
let(:group) { create :group, :public }
let(:project1) { create(:project, :public, group: group) }
let(:project2) { create(:project, :private, group: group) }
context 'all snippets visible to a user' do
let!(:snippet1) { create(:personal_snippet, :private) }
let!(:snippet2) { create(:personal_snippet, :internal) }
let!(:snippet3) { create(:personal_snippet, :public) }
let!(:project_snippet1) { create(:project_snippet, :private) }
let!(:project_snippet2) { create(:project_snippet, :internal) }
let!(:project_snippet3) { create(:project_snippet, :public) }
it "returns all private and internal snippets" do
snippets = described_class.new(user, scope: :all).execute
expect(snippets).to include(snippet2, snippet3, project_snippet2, project_snippet3)
expect(snippets).not_to include(snippet1, project_snippet1)
end
it "returns all public snippets" do
snippets = described_class.new(nil, scope: :all).execute
expect(snippets).to include(snippet3, project_snippet3)
expect(snippets).not_to include(snippet1, snippet2, project_snippet1, project_snippet2)
end
it "returns all public and internal snippets for normal user" do
snippets = described_class.new(user).execute
expect(snippets).to include(snippet2, snippet3, project_snippet2, project_snippet3)
expect(snippets).not_to include(snippet1, project_snippet1)
end
it "returns all public snippets for non authorized user" do
snippets = described_class.new(nil).execute
expect(snippets).to include(snippet3, project_snippet3)
expect(snippets).not_to include(snippet1, snippet2, project_snippet1, project_snippet2)
end
it "returns all public and authored snippets for external user" do
external_user = create(:user, :external)
authored_snippet = create(:personal_snippet, :internal, author: external_user)
snippets = described_class.new(external_user).execute
expect(snippets).to include(snippet3, project_snippet3, authored_snippet)
expect(snippets).not_to include(snippet1, snippet2, project_snippet1, project_snippet2)
end
end
context 'filter by visibility' do context 'filter by visibility' do
let!(:snippet1) { create(:personal_snippet, :private) } let!(:snippet1) { create(:personal_snippet, :private) }
...@@ -67,6 +18,7 @@ describe SnippetsFinder do ...@@ -67,6 +18,7 @@ describe SnippetsFinder do
end end
context 'filter by scope' do context 'filter by scope' do
let(:user) { create :user }
let!(:snippet1) { create(:personal_snippet, :private, author: user) } let!(:snippet1) { create(:personal_snippet, :private, author: user) }
let!(:snippet2) { create(:personal_snippet, :internal, author: user) } let!(:snippet2) { create(:personal_snippet, :internal, author: user) }
let!(:snippet3) { create(:personal_snippet, :public, author: user) } let!(:snippet3) { create(:personal_snippet, :public, author: user) }
...@@ -84,7 +36,7 @@ describe SnippetsFinder do ...@@ -84,7 +36,7 @@ describe SnippetsFinder do
expect(snippets).not_to include(snippet2, snippet3) expect(snippets).not_to include(snippet2, snippet3)
end end
it "returns all snippets for 'are_interna;' scope" do it "returns all snippets for 'are_internal' scope" do
snippets = described_class.new(user, scope: :are_internal).execute snippets = described_class.new(user, scope: :are_internal).execute
expect(snippets).to include(snippet2) expect(snippets).to include(snippet2)
...@@ -100,6 +52,8 @@ describe SnippetsFinder do ...@@ -100,6 +52,8 @@ describe SnippetsFinder do
end end
context 'filter by author' do context 'filter by author' do
let(:user) { create :user }
let(:user1) { create :user }
let!(:snippet1) { create(:personal_snippet, :private, author: user) } let!(:snippet1) { create(:personal_snippet, :private, author: user) }
let!(:snippet2) { create(:personal_snippet, :internal, author: user) } let!(:snippet2) { create(:personal_snippet, :internal, author: user) }
let!(:snippet3) { create(:personal_snippet, :public, author: user) } let!(:snippet3) { create(:personal_snippet, :public, author: user) }
...@@ -147,6 +101,10 @@ describe SnippetsFinder do ...@@ -147,6 +101,10 @@ describe SnippetsFinder do
end end
context 'filter by project' do context 'filter by project' do
let(:user) { create :user }
let(:group) { create :group, :public }
let(:project1) { create(:project, :public, group: group) }
before do before do
@snippet1 = create(:project_snippet, :private, project: project1) @snippet1 = create(:project_snippet, :private, project: project1)
@snippet2 = create(:project_snippet, :internal, project: project1) @snippet2 = create(:project_snippet, :internal, project: project1)
...@@ -203,4 +161,9 @@ describe SnippetsFinder do ...@@ -203,4 +161,9 @@ describe SnippetsFinder do
expect(snippets).to include(@snippet1) expect(snippets).to include(@snippet1)
end end
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
end
end end
...@@ -3,35 +3,86 @@ require 'spec_helper' ...@@ -3,35 +3,86 @@ require 'spec_helper'
describe Banzai::Filter::SyntaxHighlightFilter do describe Banzai::Filter::SyntaxHighlightFilter do
include FilterSpecHelper include FilterSpecHelper
shared_examples "XSS prevention" do |lang|
it "escapes HTML tags" do
# This is how a script tag inside a code block is presented to this filter
# after Markdown rendering.
result = filter(%{<pre lang="#{lang}"><code>&lt;script&gt;alert(1)&lt;/script&gt;</code></pre>})
expect(result.to_html).not_to include("<script>alert(1)</script>")
expect(result.to_html).to include("alert(1)")
end
end
context "when no language is specified" do context "when no language is specified" do
it "highlights as plaintext" do it "highlights as plaintext" do
result = filter('<pre><code>def fun end</code></pre>') result = filter('<pre><code>def fun end</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre>') expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre>')
end end
include_examples "XSS prevention", ""
end end
context "when a valid language is specified" do context "when a valid language is specified" do
it "highlights as that language" do it "highlights as that language" do
result = filter('<pre><code lang="ruby">def fun end</code></pre>') result = filter('<pre><code lang="ruby">def fun end</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre>') expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre>')
end end
include_examples "XSS prevention", "ruby"
end end
context "when an invalid language is specified" do context "when an invalid language is specified" do
it "highlights as plaintext" do it "highlights as plaintext" do
result = filter('<pre><code lang="gnuplot">This is a test</code></pre>') result = filter('<pre><code lang="gnuplot">This is a test</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>') expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext" lang="plaintext" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre>')
end end
include_examples "XSS prevention", "gnuplot"
end end
context "when Rouge formatting fails" do context "languages that should be passed through" do
%w(math mermaid plantuml).each do |lang|
context "when #{lang} is specified" do
it "highlights as plaintext but with the correct language attribute and class" do
result = filter(%{<pre><code lang="#{lang}">This is a test</code></pre>})
expect(result.to_html).to eq(%{<pre class="code highlight js-syntax-highlight #{lang}" lang="#{lang}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre>})
end
include_examples "XSS prevention", lang
end
end
end
context "when Rouge lexing fails" do
before do before do
allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError) allow_any_instance_of(Rouge::Lexers::Ruby).to receive(:stream_tokens).and_raise(StandardError)
end end
it "highlights as plaintext" do it "highlights as plaintext" do
result = filter('<pre><code lang="ruby">This is a test</code></pre>') result = filter('<pre><code lang="ruby">This is a test</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight" lang="" v-pre="true"><code>This is a test</code></pre>')
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight" lang="" v-pre="true"><code><span id="LC1" class="line" lang="">This is a test</span></code></pre>')
end
include_examples "XSS prevention", "ruby"
end
context "when Rouge lexing fails after a retry" do
before do
allow_any_instance_of(Rouge::Lexers::PlainText).to receive(:stream_tokens).and_raise(StandardError)
end
it "does not add highlighting classes" do
result = filter('<pre><code>This is a test</code></pre>')
expect(result.to_html).to eq('<pre><code>This is a test</code></pre>')
end end
include_examples "XSS prevention", "ruby"
end end
end end
...@@ -1590,7 +1590,7 @@ describe Ci::Build do ...@@ -1590,7 +1590,7 @@ describe Ci::Build do
context 'when the branch is protected' do context 'when the branch is protected' do
before do before do
create(:protected_branch, project: build.project, name: build.ref) allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end end
it { is_expected.to include(protected_variable) } it { is_expected.to include(protected_variable) }
...@@ -1598,7 +1598,7 @@ describe Ci::Build do ...@@ -1598,7 +1598,7 @@ describe Ci::Build do
context 'when the tag is protected' do context 'when the tag is protected' do
before do before do
create(:protected_tag, project: build.project, name: build.ref) allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end end
it { is_expected.to include(protected_variable) } it { is_expected.to include(protected_variable) }
...@@ -1635,7 +1635,7 @@ describe Ci::Build do ...@@ -1635,7 +1635,7 @@ describe Ci::Build do
context 'when the branch is protected' do context 'when the branch is protected' do
before do before do
create(:protected_branch, project: build.project, name: build.ref) allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end end
it { is_expected.to include(protected_variable) } it { is_expected.to include(protected_variable) }
...@@ -1643,7 +1643,7 @@ describe Ci::Build do ...@@ -1643,7 +1643,7 @@ describe Ci::Build do
context 'when the tag is protected' do context 'when the tag is protected' do
before do before do
create(:protected_tag, project: build.project, name: build.ref) allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
end end
it { is_expected.to include(protected_variable) } it { is_expected.to include(protected_variable) }
......
...@@ -549,7 +549,7 @@ describe Group do ...@@ -549,7 +549,7 @@ describe Group do
context 'when the ref is a protected branch' do context 'when the ref is a protected branch' do
before do before do
create(:protected_branch, name: 'ref', project: project) allow(project).to receive(:protected_for?).with('ref').and_return(true)
end end
it_behaves_like 'ref is protected' it_behaves_like 'ref is protected'
...@@ -557,7 +557,7 @@ describe Group do ...@@ -557,7 +557,7 @@ describe Group do
context 'when the ref is a protected tag' do context 'when the ref is a protected tag' do
before do before do
create(:protected_tag, name: 'ref', project: project) allow(project).to receive(:protected_for?).with('ref').and_return(true)
end end
it_behaves_like 'ref is protected' it_behaves_like 'ref is protected'
...@@ -571,6 +571,10 @@ describe Group do ...@@ -571,6 +571,10 @@ describe Group do
let(:variable_child_2) { create(:ci_group_variable, group: group_child_2) } let(:variable_child_2) { create(:ci_group_variable, group: group_child_2) }
let(:variable_child_3) { create(:ci_group_variable, group: group_child_3) } let(:variable_child_3) { create(:ci_group_variable, group: group_child_3) }
before do
allow(project).to receive(:protected_for?).with('ref').and_return(true)
end
it 'returns all variables belong to the group and parent groups' do it 'returns all variables belong to the group and parent groups' do
expected_array1 = [protected_variable, secret_variable] expected_array1 = [protected_variable, secret_variable]
expected_array2 = [variable_child, variable_child_2, variable_child_3] expected_array2 = [variable_child, variable_child_2, variable_child_3]
......
...@@ -2092,7 +2092,7 @@ describe Project do ...@@ -2092,7 +2092,7 @@ describe Project do
context 'when the ref is a protected branch' do context 'when the ref is a protected branch' do
before do before do
create(:protected_branch, name: 'ref', project: project) allow(project).to receive(:protected_for?).with('ref').and_return(true)
end end
it_behaves_like 'ref is protected' it_behaves_like 'ref is protected'
...@@ -2100,7 +2100,7 @@ describe Project do ...@@ -2100,7 +2100,7 @@ describe Project do
context 'when the ref is a protected tag' do context 'when the ref is a protected tag' do
before do before do
create(:protected_tag, name: 'ref', project: project) allow(project).to receive(:protected_for?).with('ref').and_return(true)
end end
it_behaves_like 'ref is protected' it_behaves_like 'ref is protected'
...@@ -2125,6 +2125,8 @@ describe Project do ...@@ -2125,6 +2125,8 @@ describe Project do
context 'when the ref is a protected branch' do context 'when the ref is a protected branch' do
before do before do
allow(project).to receive(:repository).and_call_original
allow(project).to receive_message_chain(:repository, :branch_exists?).and_return(true)
create(:protected_branch, name: 'ref', project: project) create(:protected_branch, name: 'ref', project: project)
end end
...@@ -2135,6 +2137,8 @@ describe Project do ...@@ -2135,6 +2137,8 @@ describe Project do
context 'when the ref is a protected tag' do context 'when the ref is a protected tag' do
before do before do
allow(project).to receive_message_chain(:repository, :branch_exists?).and_return(false)
allow(project).to receive_message_chain(:repository, :tag_exists?).and_return(true)
create(:protected_tag, name: 'ref', project: project) create(:protected_tag, name: 'ref', project: project)
end end
......
require 'spec_helper' require 'spec_helper'
# Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb
describe PersonalSnippetPolicy do describe PersonalSnippetPolicy do
let(:regular_user) { create(:user) } let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) } let(:external_user) { create(:user, :external) }
......
require 'spec_helper' require 'spec_helper'
# Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb
describe ProjectSnippetPolicy do describe ProjectSnippetPolicy do
let(:regular_user) { create(:user) } let(:regular_user) { create(:user) }
let(:external_user) { create(:user, :external) } let(:external_user) { create(:user, :external) }
......
...@@ -32,6 +32,27 @@ describe API::Snippets do ...@@ -32,6 +32,27 @@ describe API::Snippets do
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.size).to eq(0) expect(json_response.size).to eq(0)
end end
it 'returns 404 for non-authenticated' do
create(:personal_snippet, :internal)
get api("/snippets/")
expect(response).to have_gitlab_http_status(401)
end
it 'does not return snippets related to a project with disable feature visibility' do
project = create(:project)
create(:project_member, project: project, user: user)
public_snippet = create(:personal_snippet, :public, author: user, project: project)
project.project_feature.update_attribute(:snippets_access_level, 0)
get api("/snippets/", user)
json_response.each do |snippet|
expect(snippet["id"]).not_to eq(public_snippet.id)
end
end
end end
describe 'GET /snippets/public' do describe 'GET /snippets/public' do
......
...@@ -129,6 +129,12 @@ describe API::Todos do ...@@ -129,6 +129,12 @@ describe API::Todos do
post api("/todos/#{pending_1.id}/mark_as_done", john_doe) post api("/todos/#{pending_1.id}/mark_as_done", john_doe)
end end
it 'returns 404 if the todo does not belong to the current user' do
post api("/todos/#{pending_1.id}/mark_as_done", author_1)
expect(response.status).to eq(404)
end
end end
end end
......
...@@ -38,6 +38,12 @@ describe API::V3::Todos do ...@@ -38,6 +38,12 @@ describe API::V3::Todos do
delete v3_api("/todos/#{pending_1.id}", john_doe) delete v3_api("/todos/#{pending_1.id}", john_doe)
end end
it 'returns 404 if the todo does not belong to the current user' do
delete v3_api("/todos/#{pending_1.id}", author_1)
expect(response.status).to eq(404)
end
end end
end end
......
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe Search::SnippetService do describe Search::SnippetService do
let(:author) { create(:author) } let(:author) { create(:author) }
let(:project) { create(:project) } let(:project) { create(:project, :public) }
let!(:public_snippet) { create(:snippet, :public, content: 'password: XXX') } let!(:public_snippet) { create(:snippet, :public, content: 'password: XXX') }
let!(:internal_snippet) { create(:snippet, :internal, content: 'password: XXX') } let!(:internal_snippet) { create(:snippet, :internal, content: 'password: XXX') }
......
...@@ -256,7 +256,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do ...@@ -256,7 +256,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
end end
end end
context 'user has chosen an existing nested namespace and name for the project' do context 'user has chosen an existing nested namespace and name for the project', :postgresql do
let(:parent_namespace) { create(:group, name: 'foo', owner: user) } let(:parent_namespace) { create(:group, name: 'foo', owner: user) }
let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) } let(:nested_namespace) { create(:group, name: 'bar', parent: parent_namespace) }
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
...@@ -274,7 +274,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do ...@@ -274,7 +274,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
end end
end end
context 'user has chosen a non-existent nested namespaces and name for the project' do context 'user has chosen a non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do it 'takes the selected namespace and name' do
...@@ -305,10 +305,14 @@ shared_examples 'a GitHub-ish import controller: POST create' do ...@@ -305,10 +305,14 @@ shared_examples 'a GitHub-ish import controller: POST create' do
end end
end end
context 'user has chosen existent and non-existent nested namespaces and name for the project' do context 'user has chosen existent and non-existent nested namespaces and name for the project', :postgresql do
let(:test_name) { 'test_name' } let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo', owner: user) } let!(:parent_namespace) { create(:group, name: 'foo', owner: user) }
before do
parent_namespace.add_owner(user)
end
it 'takes the selected namespace and name' do it 'takes the selected namespace and name' do
expect(Gitlab::LegacyGithubImport::ProjectCreator) expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider) .to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
...@@ -325,6 +329,53 @@ shared_examples 'a GitHub-ish import controller: POST create' do ...@@ -325,6 +329,53 @@ shared_examples 'a GitHub-ish import controller: POST create' do
expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } } expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } }
.to change { Namespace.count }.by(2) .to change { Namespace.count }.by(2)
end end
it 'does not create a new namespace under the user namespace' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
expect { post :create, { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name, format: :js } }
.not_to change { Namespace.count }
end
end
context 'user cannot create a subgroup inside a group is not a member of' do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:group, name: 'foo') }
it 'does not take the selected namespace and name' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js }
end
it 'does not create the namespaces' do
allow(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } }
.not_to change { Namespace.count }
end
end
context 'user can use a group without having permissions to create a group' do
let(:test_name) { 'test_name' }
let!(:group) { create(:group, name: 'foo') }
it 'takes the selected namespace and name' do
group.add_owner(user)
user.update!(can_create_group: false)
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).with(provider_repo, test_name, group, user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
post :create, { target_namespace: 'foo', new_name: test_name, format: :js }
end
end end
context 'when user can not create projects in the chosen namespace' do context 'when user can not create projects in the chosen namespace' do
......
This diff is collapsed.
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