diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f1dcf99062958081898b8776d970727ee91ecfa0..83a906932d02e1f06c4c31a5ce6cd73d7e740250 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -92,9 +92,7 @@ update-knapsack:
     - export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
     - export KNAPSACK_GENERATE_REPORT=true
     - cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH}
-    - knapsack spinach "-r rerun"
-    # retry failed tests 3 times
-    - retry '[ ! -e tmp/spinach-rerun.txt ] || bin/spinach -r rerun $(cat tmp/spinach-rerun.txt)'
+    - knapsack spinach "-r rerun" || retry '[ ! -e tmp/spinach-rerun.txt ] || bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
   artifacts:
     paths:
     - knapsack/
diff --git a/.rubocop.yml b/.rubocop.yml
index c637f5e12f56e6541ef0e2ec4ddcb193fcaf37a1..dbdabbb9d4cb6adb83fd661c836e0b529b92e157 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -349,7 +349,7 @@ Style/MultilineArrayBraceLayout:
 
 # Avoid multi-line chains of blocks.
 Style/MultilineBlockChain:
-  Enabled: false
+  Enabled: true
 
 # Ensures newlines after multiline block do statements.
 Style/MultilineBlockLayout:
diff --git a/CHANGELOG b/CHANGELOG
index 7a6a14919daba9eef49be80e4d2b5f8542ca323f..2aed8eb322b7dba43fc591a987b129b5944215c1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
 
 v 8.9.0 (unreleased)
   - Fix Error 500 when using closes_issues API with an external issue tracker
+  - Add more information into RSS feed for issues (Alexander Matyushentsev)
   - Bulk assign/unassign labels to issues.
   - Ability to prioritize labels !4009 / !3205 (Thijs Wouters)
   - Fix endless redirections when accessing user OAuth applications when they are disabled
@@ -38,6 +39,8 @@ v 8.9.0 (unreleased)
   - Add option to project to only allow merge requests to be merged if the build succeeds (Rui Santos)
   - Fix issues filter when ordering by milestone
   - Added artifacts:when to .gitlab-ci.yml - this requires GitLab Runner 1.3
+  - Bamboo Service: Fix missing credentials & URL handling when base URL contains a path (Benjamin Schmid)
+  - TeamCity Service: Fix URL handling when base URL contains a path
   - Todos will display target state if issuable target is 'Closed' or 'Merged'
   - Fix bug when sorting issues by milestone due date and filtering by two or more labels
   - Add support for using Yubikeys (U2F) for two-factor authentication
@@ -72,6 +75,8 @@ v 8.9.0 (unreleased)
   - Cache on the database if a project has an active external issue tracker.
   - Put project Labels and Milestones pages links under Issues and Merge Requests tabs as subnav
   - All classes in the Banzai::ReferenceParser namespace are now instrumented
+  - Remove deprecated issues_tracker and issues_tracker_id from project model
+  - Allow users to create confidential issues in private projects
 
 v 8.8.5 (unreleased)
   - Ensure branch cleanup regardless of whether the GitHub import process succeeds
diff --git a/Gemfile b/Gemfile
index f56daa099a275552f7e4f3dd50b740627f6c4e0c..3b2878930026892a3fea2da2ff1febd83673271b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -248,7 +248,7 @@ end
 
 group :development do
   gem "foreman"
-  gem 'brakeman', '~> 3.2.0', require: false
+  gem 'brakeman', '~> 3.3.0', require: false
 
   gem 'letter_opener_web', '~> 1.3.0'
   gem 'quiet_assets', '~> 1.0.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index 2b2e2d2bb07734ace9a309bd9c590c4594279485..209f29de1e0e2dbaa269c0027704869a3374f3c9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -97,16 +97,7 @@ GEM
     bootstrap-sass (3.3.6)
       autoprefixer-rails (>= 5.2.1)
       sass (>= 3.3.4)
-    brakeman (3.2.1)
-      erubis (~> 2.6)
-      haml (>= 3.0, < 5.0)
-      highline (>= 1.6.20, < 2.0)
-      ruby2ruby (~> 2.3.0)
-      ruby_parser (~> 3.8.1)
-      safe_yaml (>= 1.0)
-      sass (~> 3.0)
-      slim (>= 1.3.6, < 4.0)
-      terminal-table (~> 1.4)
+    brakeman (3.3.2)
     browser (2.0.3)
     builder (3.2.2)
     bullet (5.0.0)
@@ -340,7 +331,6 @@ GEM
     hashie (3.4.3)
     health_check (1.5.1)
       rails (>= 2.3.0)
-    highline (1.7.8)
     hipchat (1.5.2)
       httparty
       mimemagic
@@ -645,10 +635,7 @@ GEM
     ruby-saml (1.1.2)
       nokogiri (>= 1.5.10)
       uuid (~> 2.3)
-    ruby2ruby (2.3.0)
-      ruby_parser (~> 3.1)
-      sexp_processor (~> 4.0)
-    ruby_parser (3.8.1)
+    ruby_parser (3.8.2)
       sexp_processor (~> 4.1)
     rubyntlm (0.5.2)
     rubypants (0.2.0)
@@ -658,7 +645,7 @@ GEM
     safe_yaml (1.0.4)
     sanitize (2.1.0)
       nokogiri (>= 1.4.4)
-    sass (3.4.21)
+    sass (3.4.22)
     sass-rails (5.0.4)
       railties (>= 4.0.0, < 5.0)
       sass (~> 3.1)
@@ -707,9 +694,6 @@ GEM
       tilt (>= 1.3, < 3)
     six (0.2.0)
     slack-notifier (1.2.1)
-    slim (3.0.6)
-      temple (~> 0.7.3)
-      tilt (>= 1.3.3, < 2.1)
     slop (3.6.0)
     spinach (0.8.10)
       colorize
@@ -750,10 +734,8 @@ GEM
       railties (>= 3.2.5, < 6)
     teaspoon-jasmine (2.2.0)
       teaspoon (>= 1.0.0)
-    temple (0.7.6)
     term-ansicolor (1.3.2)
       tins (~> 1.0)
-    terminal-table (1.5.2)
     test_after_commit (0.4.2)
       activerecord (>= 3.2)
     thin (1.6.4)
@@ -762,7 +744,7 @@ GEM
       rack (~> 1.0)
     thor (0.19.1)
     thread_safe (0.3.5)
-    tilt (2.0.2)
+    tilt (2.0.5)
     timecop (0.8.1)
     timfel-krb5-auth (0.8.3)
     tinder (1.10.1)
@@ -851,7 +833,7 @@ DEPENDENCIES
   better_errors (~> 1.0.1)
   binding_of_caller (~> 0.7.2)
   bootstrap-sass (~> 3.3.0)
-  brakeman (~> 3.2.0)
+  brakeman (~> 3.3.0)
   browser (~> 2.0.3)
   bullet
   bundler-audit
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index 131a16dad9b2ac28c40a76ced4491571b5b45766..014b9b43ff26f955f969a883defd154817555721 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -42,7 +42,7 @@ class JwtController < ApplicationController
   end
 
   def authenticate_user(login, password)
-    user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password)
+    user = Gitlab::Auth.find_with_user_password(login, password)
     Gitlab::Auth.rate_limit!(request.ip, success: user.present?, login: login)
     user
   end
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index 348d6cf4d96c51347a2ae056f0ef99977d31b6c4..f907d63258b19e20e27be07f83c365dde9f5cd67 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -43,7 +43,7 @@ class Projects::GitHttpController < Projects::ApplicationController
     return if project && project.public? && upload_pack?
 
     authenticate_or_request_with_http_basic do |login, password|
-      auth_result = Gitlab::Auth.find(login, password, project: project, ip: request.ip)
+      auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip)
 
       if auth_result.type == :ci && upload_pack?
         @ci = true
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index 01cbf91c658b8a9a5d7a2d2652dce5eba14925ef..00ff161103932ede759303894fecd0cbda80d564 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -51,7 +51,7 @@ class SnippetsFinder
     snippets = project.snippets.fresh
 
     if current_user
-      if project.team.member?(current_user.id) || current_user.admin?
+      if project.team.member?(current_user) || current_user.admin?
         snippets
       else
         snippets.public_and_internal
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 44515550d9ed6eb391df4a162666a409d07f4a83..aea946f9224b35f0243db4ab807925e969ca7a6f 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -533,7 +533,7 @@ class Ability
     def filter_confidential_issues_abilities(user, issue, rules)
       return rules if user.admin? || !issue.confidential?
 
-      unless issue.author == user || issue.assignee == user || issue.project.team.member?(user.id)
+      unless issue.author == user || issue.assignee == user || issue.project.team.member?(user, Gitlab::Access::REPORTER)
         rules.delete(:admin_issue)
         rules.delete(:read_issue)
         rules.delete(:update_issue)
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 235922710ad6a6f56699793ea47ce9199ca7a03a..1bdf9c011b2821a11845b00225670c28b9525860 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -51,10 +51,18 @@ class Issue < ActiveRecord::Base
   end
 
   def self.visible_to_user(user)
-    return where(confidential: false) if user.blank?
+    return where('issues.confidential IS NULL OR issues.confidential IS FALSE') if user.blank?
     return all if user.admin?
 
-    where('issues.confidential = false OR (issues.confidential = true AND (issues.author_id = :user_id OR issues.assignee_id = :user_id OR issues.project_id IN(:project_ids)))', user_id: user.id, project_ids: user.authorized_projects.select(:id))
+    where('
+      issues.confidential IS NULL
+      OR issues.confidential IS FALSE
+      OR (issues.confidential = TRUE
+        AND (issues.author_id = :user_id
+          OR issues.assignee_id = :user_id
+          OR issues.project_id IN(:project_ids)))',
+      user_id: user.id,
+      project_ids: user.authorized_projects(Gitlab::Access::REPORTER).select(:id))
   end
 
   def self.reference_prefix
diff --git a/app/models/note.rb b/app/models/note.rb
index 585d8c4ad843f1f7a715168b51b4a2a4af8b9edd..58133f1581fa9b47f9b70c23f957e1f58801f3fc 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -88,22 +88,9 @@ class Note < ActiveRecord::Base
       table   = arel_table
       pattern = "%#{query}%"
 
-      found_notes = joins('LEFT JOIN issues ON issues.id = noteable_id').
-        where(table[:note].matches(pattern))
-
-      if as_user
-        found_notes.where('
-          issues.confidential IS NULL
-          OR issues.confidential IS FALSE
-          OR (issues.confidential IS TRUE
-            AND (issues.author_id = :user_id
-            OR issues.assignee_id = :user_id
-            OR issues.project_id IN(:project_ids)))',
-          user_id: as_user.id,
-          project_ids: as_user.authorized_projects.select(:id))
-      else
-        found_notes.where('issues.confidential IS NULL OR issues.confidential IS FALSE')
-      end
+      Note.joins('LEFT JOIN issues ON issues.id = noteable_id').
+        where(table[:note].matches(pattern)).
+        merge(Issue.visible_to_user(as_user))
     end
   end
 
diff --git a/app/models/project.rb b/app/models/project.rb
index e2f7ffe493c328946aa75668686d24296de282eb..dfa99fe0df273ac1174e902f3ea5c18c236d5363 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -146,7 +146,6 @@ class Project < ActiveRecord::Base
               message: Gitlab::Regex.project_path_regex_message }
   validates :issues_enabled, :merge_requests_enabled,
             :wiki_enabled, inclusion: { in: [true, false] }
-  validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
   validates :namespace, presence: true
   validates_uniqueness_of :name, scope: :namespace_id
   validates_uniqueness_of :path, scope: :namespace_id
@@ -589,10 +588,6 @@ class Project < ActiveRecord::Base
     update_column(:has_external_issue_tracker, services.external_issue_trackers.any?)
   end
 
-  def can_have_issues_tracker_id?
-    self.issues_enabled && !self.default_issues_tracker?
-  end
-
   def build_missing_services
     services_templates = Service.where(template: true)
 
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 1d1780dcfbf3e221f8d8cb22988b79774605af7b..b5c76e4d4fef5ca93a219b731f3765fd71d568d9 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -1,6 +1,4 @@
 class BambooService < CiService
-  include HTTParty
-
   prop_accessor :bamboo_url, :build_key, :username, :password
 
   validates :bamboo_url, presence: true, url: true, if: :activated?
@@ -61,18 +59,7 @@ class BambooService < CiService
   end
 
   def build_info(sha)
-    url = URI.join(bamboo_url, "/rest/api/latest/result?label=#{sha}").to_s
-
-    if username.blank? && password.blank?
-      @response = HTTParty.get(url, verify: false)
-    else
-      url << '&os_authType=basic'
-      auth = {
-        username: username,
-        password: password
-      }
-      @response = HTTParty.get(url, verify: false, basic_auth: auth)
-    end
+    @response = get_path("rest/api/latest/result?label=#{sha}")
   end
 
   def build_page(sha, ref)
@@ -80,11 +67,11 @@ class BambooService < CiService
 
     if @response.code != 200 || @response['results']['results']['size'] == '0'
       # If actual build link can't be determined, send user to build summary page.
-      URI.join(bamboo_url, "/browse/#{build_key}").to_s
+      URI.join("#{bamboo_url}/", "browse/#{build_key}").to_s
     else
       # If actual build link is available, go to build result page.
       result_key = @response['results']['results']['result']['planResultKey']['key']
-      URI.join(bamboo_url, "/browse/#{result_key}").to_s
+      URI.join("#{bamboo_url}/", "browse/#{result_key}").to_s
     end
   end
 
@@ -112,8 +99,27 @@ class BambooService < CiService
   def execute(data)
     return unless supported_events.include?(data[:object_kind])
 
-    # Bamboo requires a GET and does not take any data.
-    url = URI.join(bamboo_url, "/updateAndBuild.action?buildKey=#{build_key}").to_s
-    self.class.get(url, verify: false)
+    get_path("updateAndBuild.action?buildKey=#{build_key}")
+  end
+
+  private
+
+  def build_url(path)
+    URI.join("#{bamboo_url}/", path).to_s
+  end
+
+  def get_path(path)
+    url = build_url(path)
+
+    if username.blank? && password.blank?
+      HTTParty.get(url, verify: false)
+    else
+      url << '&os_authType=basic'
+      HTTParty.get(url, verify: false,
+                        basic_auth: {
+                          username: username,
+                          password: password
+                        })
+    end
   end
 end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index 6ae9b16d3ce49635e3eb0f79a06cd2fe9843a1ac..87ecb3b8b868d2fad8211cbdbe74cbd4c634fd42 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -38,9 +38,9 @@ class IssueTrackerService < Service
       if enabled_in_gitlab_config
         self.properties = {
           title: issues_tracker['title'],
-          project_url: add_issues_tracker_id(issues_tracker['project_url']),
-          issues_url: add_issues_tracker_id(issues_tracker['issues_url']),
-          new_issue_url: add_issues_tracker_id(issues_tracker['new_issue_url'])
+          project_url: issues_tracker['project_url'],
+          issues_url: issues_tracker['issues_url'],
+          new_issue_url: issues_tracker['new_issue_url']
         }
       else
         self.properties = {}
@@ -83,16 +83,4 @@ class IssueTrackerService < Service
   def issues_tracker
     Gitlab.config.issues_tracker[to_param]
   end
-
-  def add_issues_tracker_id(url)
-    if self.project
-      id = self.project.issues_tracker_id
-
-      if id
-        url = url.gsub(":issues_tracker_id", id)
-      end
-    end
-
-    url
-  end
 end
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index b0dcb52eba15db9b1f03f6f649d62a5125a9e3e7..a4a967c9bc94b02e6048a2dce870f8fb5f8a9a99 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -1,6 +1,4 @@
 class TeamcityService < CiService
-  include HTTParty
-
   prop_accessor :teamcity_url, :build_type, :username, :password
 
   validates :teamcity_url, presence: true, url: true, if: :activated?
@@ -64,15 +62,7 @@ class TeamcityService < CiService
   end
 
   def build_info(sha)
-    url = URI.join(
-      teamcity_url,
-      "/httpAuth/app/rest/builds/branch:unspecified:any,number:#{sha}"
-    ).to_s
-    auth = {
-      username: username,
-      password: password
-    }
-    @response = HTTParty.get(url, verify: false, basic_auth: auth)
+    @response = get_path("httpAuth/app/rest/builds/branch:unspecified:any,number:#{sha}")
   end
 
   def build_page(sha, ref)
@@ -81,14 +71,11 @@ class TeamcityService < CiService
     if @response.code != 200
       # If actual build link can't be determined,
       # send user to build summary page.
-      URI.join(teamcity_url, "/viewLog.html?buildTypeId=#{build_type}").to_s
+      build_url("viewLog.html?buildTypeId=#{build_type}")
     else
       # If actual build link is available, go to build result page.
       built_id = @response['build']['id']
-      URI.join(
-        teamcity_url,
-        "/viewLog.html?buildId=#{built_id}&buildTypeId=#{build_type}"
-      ).to_s
+      build_url("viewLog.html?buildId=#{built_id}&buildTypeId=#{build_type}")
     end
   end
 
@@ -123,8 +110,8 @@ class TeamcityService < CiService
 
     branch = Gitlab::Git.ref_name(data[:ref])
 
-    self.class.post(
-      URI.join(teamcity_url, '/httpAuth/app/rest/buildQueue').to_s,
+    HTTParty.post(
+      build_url('httpAuth/app/rest/buildQueue'),
       body: "<build branchName=\"#{branch}\">"\
             "<buildType id=\"#{build_type}\"/>"\
             '</build>',
@@ -132,4 +119,18 @@ class TeamcityService < CiService
       basic_auth: auth
     )
   end
+
+  private
+
+  def build_url(path)
+    URI.join("#{teamcity_url}/", path).to_s
+  end
+
+  def get_path(path)
+    HTTParty.get(build_url(path), verify: false,
+                                  basic_auth: {
+                                    username: username,
+                                    password: password
+                                  })
+  end
 end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 70a8bbaba6575f2a8e307e3fc6773c26ed999ddb..e29e854860ae238f238e95af9cb3e5c99afb371c 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -131,8 +131,14 @@ class ProjectTeam
     max_member_access(user.id) == Gitlab::Access::MASTER
   end
 
-  def member?(user_id)
-    !!find_member(user_id)
+  def member?(user, min_member_access = nil)
+    member = !!find_member(user.id)
+
+    if min_member_access
+      member && max_member_access(user.id) >= min_member_access
+    else
+      member
+    end
   end
 
   def human_max_access(user_id)
diff --git a/app/models/user.rb b/app/models/user.rb
index 7afbfbf112a5f745d0edd28cdc282cf11ba87955..a5b3c8afe51b539e4f635b2056a3103abba15e6f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -405,8 +405,8 @@ class User < ActiveRecord::Base
   end
 
   # Returns projects user is authorized to access.
-  def authorized_projects
-    Project.where("projects.id IN (#{projects_union.to_sql})")
+  def authorized_projects(min_access_level = nil)
+    Project.where("projects.id IN (#{projects_union(min_access_level).to_sql})")
   end
 
   def viewable_starred_projects
@@ -824,11 +824,19 @@ class User < ActiveRecord::Base
 
   private
 
-  def projects_union
-    Gitlab::SQL::Union.new([personal_projects.select(:id),
-                            groups_projects.select(:id),
-                            projects.select(:id),
-                            groups.joins(:shared_projects).select(:project_id)])
+  def projects_union(min_access_level = nil)
+    relations = [personal_projects.select(:id),
+                 groups_projects.select(:id),
+                 projects.select(:id),
+                 groups.joins(:shared_projects).select(:project_id)]
+
+
+    if min_access_level
+      scope = { access_level: Gitlab::Access.values.select { |access| access >= min_access_level } }
+      relations = [relations.shift] + relations.map { |relation| relation.where(members: scope) }
+    end
+
+    Gitlab::SQL::Union.new(relations)
   end
 
   def ci_projects_union
diff --git a/app/views/issues/_issue.atom.builder b/app/views/issues/_issue.atom.builder
index 68a2d19e58dc8a9add675fdc0b29c68b81ea3147..968318741447739462ddfd5834e35e6582c6c5ef 100644
--- a/app/views/issues/_issue.atom.builder
+++ b/app/views/issues/_issue.atom.builder
@@ -5,10 +5,28 @@ xml.entry do
   xml.updated issue.created_at.xmlschema
   xml.media   :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
 
-  xml.author do |author|
+  xml.author do
     xml.name issue.author_name
     xml.email issue.author_email
   end
 
   xml.summary issue.title
+  xml.description issue.description if issue.description
+  xml.milestone issue.milestone.title if issue.milestone
+  xml.due_date issue.due_date if issue.due_date
+
+  unless issue.labels.empty?
+    xml.labels do
+      issue.labels.each do |label|
+        xml.label label.name
+      end
+    end
+  end
+
+  if issue.assignee
+    xml.assignee do
+      xml.name issue.assignee.name
+      xml.email issue.assignee.email
+    end
+  end
 end
diff --git a/app/views/projects/pipelines/_head.html.haml b/app/views/projects/pipelines/_head.html.haml
index f278d4e0538c9e6ae4bd1e28497307da726f18a3..d0ba0d27d7c9559eec3417167235b1ebe1a98bc0 100644
--- a/app/views/projects/pipelines/_head.html.haml
+++ b/app/views/projects/pipelines/_head.html.haml
@@ -5,11 +5,9 @@
         = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
           %span
             Pipelines
-            %span.badge.count.ci_counter= number_with_delimiter(@project.pipelines.running_or_pending.count)
 
     - if project_nav_tab? :builds
       = nav_link(controller: %w(builds)) do
         = link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
           %span
             Builds
-            %span.badge.count.builds_counter= number_with_delimiter(@project.running_or_pending_build_count)
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 17e2a7e92909d51c6d2b3951369f31fc1cf9c2cd..c30bdb0ae913279c1ecfa1c027b4d111b1fcc6c5 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -35,13 +35,13 @@
       .clearfix
       .error-alert
 
-- if issuable.is_a?(Issue) && !issuable.project.private?
+- if issuable.is_a?(Issue)
   .form-group
     .col-sm-offset-2.col-sm-10
       .checkbox
         = f.label :confidential do
           = f.check_box :confidential
-          This issue is confidential and should only be visible to team members
+          This issue is confidential and should only be visible to team members with at least Reporter access.
 
 - if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
   - has_due_date = issuable.has_attribute?(:due_date)
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb
index 8dc8e270afc5f3fccfa2a0d928476572dd352dda..618dba74151b52275cfdaba7698f82c3ba496710 100644
--- a/config/initializers/doorkeeper.rb
+++ b/config/initializers/doorkeeper.rb
@@ -12,7 +12,7 @@ Doorkeeper.configure do
   end
 
   resource_owner_from_credentials do |routes|
-    Gitlab::Auth.find_in_gitlab_or_ldap(params[:username], params[:password])
+    Gitlab::Auth.find_with_user_password(params[:username], params[:password])
   end
 
   # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
diff --git a/db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb b/db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb
new file mode 100644
index 0000000000000000000000000000000000000000..477b2106dead5e5d23b06f0c5bafb93d26476733
--- /dev/null
+++ b/db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb
@@ -0,0 +1,6 @@
+class RemoveDeprecatedIssuesTrackerColumnsFromProjects < ActiveRecord::Migration
+  def change
+    remove_column :projects, :issues_tracker, :string, default: 'gitlab', null: false
+    remove_column :projects, :issues_tracker_id, :string
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 91b9cb0a98a8569e3a8cdc6888571c03d8a06ca6..c1e447d3cdaa4f74300adc7f095fcebe193d63ee 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -752,8 +752,6 @@ ActiveRecord::Schema.define(version: 20160610301627) do
     t.boolean  "merge_requests_enabled",             default: true,     null: false
     t.boolean  "wiki_enabled",                       default: true,     null: false
     t.integer  "namespace_id"
-    t.string   "issues_tracker",                     default: "gitlab", null: false
-    t.string   "issues_tracker_id"
     t.boolean  "snippets_enabled",                   default: true,     null: false
     t.datetime "last_activity_at"
     t.string   "import_url"
diff --git a/lib/api/session.rb b/lib/api/session.rb
index 56e69b2366f0c6c06fa957b8892a58d7ed19145b..56c202f129435eedad105f015b8a845afb4f5994 100644
--- a/lib/api/session.rb
+++ b/lib/api/session.rb
@@ -11,7 +11,7 @@ module API
     # Example Request:
     #  POST /session
     post "/session" do
-      user = Gitlab::Auth.find_in_gitlab_or_ldap(params[:email] || params[:login], params[:password])
+      user = Gitlab::Auth.find_with_user_password(params[:email] || params[:login], params[:password])
 
       return unauthorized! unless user
       present user, with: Entities::UserLogin
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 076e2af7d38eb07622c9ae7824a5ae29433ea7cc..db1704af75ebb26077ce156ea508f78520f8b423 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -3,14 +3,14 @@ module Gitlab
     Result = Struct.new(:user, :type)
 
     class << self
-      def find(login, password, project:, ip:)
+      def find_for_git_client(login, password, project:, ip:)
         raise "Must provide an IP for rate limiting" if ip.nil?
 
         result = Result.new
 
         if valid_ci_request?(login, password, project)
           result.type = :ci
-        elsif result.user = find_in_gitlab_or_ldap(login, password)
+        elsif result.user = find_with_user_password(login, password)
           result.type = :gitlab_or_ldap
         elsif result.user = oauth_access_token_check(login, password)
           result.type = :oauth
@@ -20,7 +20,7 @@ module Gitlab
         result
       end
 
-      def find_in_gitlab_or_ldap(login, password)
+      def find_with_user_password(login, password)
         user = User.by_login(login)
 
         # If no user is found, or it's an LDAP server, try LDAP.
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 9e09d2e118d68f28e23e933656d9a2fe9047e029..adbf5941a962153730b0c4ca7a99d5707ff573a8 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -95,7 +95,7 @@ module Grack
     end
 
     def authenticate_user(login, password)
-      user = Gitlab::Auth.find_in_gitlab_or_ldap(login, password)
+      user = Gitlab::Auth.find_with_user_password(login, password)
 
       unless user
         user = oauth_access_token_check(login, password)
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 78be7e3dc354b8e88ba13d79397535575e1bafad..cbaa3e0b7b2a537b405b201083cfc037576d0855 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -105,6 +105,15 @@ describe Projects::IssuesController do
         expect(assigns(:issues)).to eq [issue]
       end
 
+      it 'should not list confidential issues for project members with guest role' do
+        sign_in(member)
+        project.team << [member, :guest]
+
+        get_issues
+
+        expect(assigns(:issues)).to eq [issue]
+      end
+
       it 'should list confidential issues for author' do
         sign_in(author)
         get_issues
@@ -148,7 +157,7 @@ describe Projects::IssuesController do
 
     shared_examples_for 'restricted action' do |http_status|
       it 'returns 404 for guests' do
-        sign_out :user
+        sign_out(:user)
         go(id: unescaped_parameter_value.to_param)
 
         expect(response).to have_http_status :not_found
@@ -161,6 +170,14 @@ describe Projects::IssuesController do
         expect(response).to have_http_status :not_found
       end
 
+      it 'returns 404 for project members with guest role' do
+        sign_in(member)
+        project.team << [member, :guest]
+        go(id: unescaped_parameter_value.to_param)
+
+        expect(response).to have_http_status :not_found
+      end
+
       it "returns #{http_status[:success]} for author" do
         sign_in(author)
         go(id: unescaped_parameter_value.to_param)
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index da8d97c9f82c27f0a429833be294e4de1dc8e2ae..5c8ddbebf0d3db656e11aefc22f5bbf40313e43a 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -67,9 +67,6 @@ FactoryGirl.define do
           'new_issue_url' => 'http://redmine/projects/project_name_in_redmine/issues/new'
         }
       )
-
-      project.issues_tracker = 'redmine'
-      project.issues_tracker_id = 'project_name_in_redmine'
     end
   end
 
@@ -84,9 +81,6 @@ FactoryGirl.define do
           'new_issue_url' => 'http://jira.example/secure/CreateIssue.jspa'
         }
       )
-
-      project.issues_tracker = 'jira'
-      project.issues_tracker_id = 'project_name_in_jira'
     end
   end
 end
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index b710cb3c72ff33b85d85de20b73bb0d9e954e48f..4dd9548cfc51737649d28629e63851f771c4f7d7 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -5,8 +5,6 @@ describe "Dashboard Issues Feed", feature: true  do
     let!(:user)     { create(:user) }
     let!(:project1) { create(:project) }
     let!(:project2) { create(:project) }
-    let!(:issue1)   { create(:issue, author: user, assignee: user, project: project1) }
-    let!(:issue2)   { create(:issue, author: user, assignee: user, project: project2) }
 
     before do
       project1.team << [user, :master]
@@ -14,16 +12,51 @@ describe "Dashboard Issues Feed", feature: true  do
     end
 
     describe "atom feed" do
-      it "should render atom feed via private token" do
+      it "renders atom feed via private token" do
         visit issues_dashboard_path(:atom, private_token: user.private_token)
 
-        expect(response_headers['Content-Type']).
-          to have_content('application/atom+xml')
+        expect(response_headers['Content-Type']).to have_content('application/atom+xml')
         expect(body).to have_selector('title', text: "#{user.name} issues")
-        expect(body).to have_selector('author email', text: issue1.author_email)
-        expect(body).to have_selector('entry summary', text: issue1.title)
-        expect(body).to have_selector('author email', text: issue2.author_email)
-        expect(body).to have_selector('entry summary', text: issue2.title)
+      end
+
+      context "issue with basic fields" do
+        let!(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'test desc') }
+
+        it "renders issue fields" do
+          visit issues_dashboard_path(:atom, private_token: user.private_token)
+
+          entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
+
+          expect(entry).to be_present
+          expect(entry).to have_selector('author email', text: issue2.author_email)
+          expect(entry).to have_selector('assignee email', text: issue2.author_email)
+          expect(entry).not_to have_selector('labels')
+          expect(entry).not_to have_selector('milestone')
+          expect(entry).to have_selector('description', text: issue2.description)
+        end
+      end
+
+      context "issue with label and milestone" do
+        let!(:milestone1) { create(:milestone, project: project1, title: 'v1') }
+        let!(:label1)     { create(:label, project: project1, title: 'label1') }
+        let!(:issue1)     { create(:issue, author: user, assignee: user, project: project1, milestone: milestone1) }
+
+        before do
+          issue1.labels << label1
+        end
+
+        it "renders issue label and milestone info" do
+          visit issues_dashboard_path(:atom, private_token: user.private_token)
+
+          entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
+
+          expect(entry).to be_present
+          expect(entry).to have_selector('author email', text: issue1.author_email)
+          expect(entry).to have_selector('assignee email', text: issue1.author_email)
+          expect(entry).to have_selector('labels label', text: label1.title)
+          expect(entry).to have_selector('milestone', text: milestone1.title)
+          expect(entry).not_to have_selector('description')
+        end
       end
     end
   end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index eae61a54dfc5480a28eeb178536ea78f8817dff8..831ae7fb69c51daa7c51fe82e7c5507bf5e989c2 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -7,10 +7,7 @@ describe IssuesHelper do
 
   describe "url_for_project_issues" do
     let(:project_url) { ext_project.external_issue_tracker.project_url }
-    let(:ext_expected) do
-      project_url.gsub(':project_id', ext_project.id.to_s)
-                 .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
-    end
+    let(:ext_expected) { project_url.gsub(':project_id', ext_project.id.to_s) }
     let(:int_expected) { polymorphic_path([@project.namespace, project]) }
 
     it "should return internal path if used internal tracker" do
@@ -56,11 +53,7 @@ describe IssuesHelper do
 
   describe "url_for_issue" do
     let(:issues_url) { ext_project.external_issue_tracker.issues_url}
-    let(:ext_expected) do
-      issues_url.gsub(':id', issue.iid.to_s)
-        .gsub(':project_id', ext_project.id.to_s)
-        .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
-    end
+    let(:ext_expected) { issues_url.gsub(':id', issue.iid.to_s).gsub(':project_id', ext_project.id.to_s) }
     let(:int_expected) { polymorphic_path([@project.namespace, project, issue]) }
 
     it "should return internal path if used internal tracker" do
@@ -106,10 +99,7 @@ describe IssuesHelper do
 
   describe 'url_for_new_issue' do
     let(:issues_url) { ext_project.external_issue_tracker.new_issue_url }
-    let(:ext_expected) do
-      issues_url.gsub(':project_id', ext_project.id.to_s)
-        .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
-    end
+    let(:ext_expected) { issues_url.gsub(':project_id', ext_project.id.to_s) }
     let(:int_expected) { new_namespace_project_issue_path(project.namespace, project) }
 
     it "should return internal path if used internal tracker" do
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index 697d10bbf708ee5cb0620cfa15014173c9966988..f181125156bf5a6e5994625ddefaffcf5b50caf3 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -69,6 +69,18 @@ describe Banzai::Filter::RedactorFilter, lib: true do
         expect(doc.css('a').length).to eq 0
       end
 
+      it 'removes references for project members with guest role' do
+        member = create(:user)
+        project = create(:empty_project, :public)
+        project.team << [member, :guest]
+        issue = create(:issue, :confidential, project: project)
+
+        link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
+        doc = filter(link, current_user: member)
+
+        expect(doc.css('a').length).to eq 0
+      end
+
       it 'allows references for author' do
         author = create(:user)
         project = create(:empty_project, :public)
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index a814ad2a4e74a634fe6ef3c39f0f8594eeb64a98..7bec1367156e556f2aa58734338f48c0854a5296 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
 describe Gitlab::Auth, lib: true do
   let(:gl_auth) { described_class }
 
-  describe 'find' do
+  describe 'find_for_git_client' do
     it 'recognizes CI' do
       token = '123'
       project = create(:empty_project)
@@ -11,7 +11,7 @@ describe Gitlab::Auth, lib: true do
       ip = 'ip'
 
       expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'gitlab-ci-token')
-      expect(gl_auth.find('gitlab-ci-token', token, project: project, ip: ip)).to eq(Gitlab::Auth::Result.new(nil, :ci))
+      expect(gl_auth.find_for_git_client('gitlab-ci-token', token, project: project, ip: ip)).to eq(Gitlab::Auth::Result.new(nil, :ci))
     end
 
     it 'recognizes master passwords' do
@@ -19,7 +19,7 @@ describe Gitlab::Auth, lib: true do
       ip = 'ip'
 
       expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: user.username)
-      expect(gl_auth.find(user.username, 'password', project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, :gitlab_or_ldap))
+      expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, :gitlab_or_ldap))
     end
 
     it 'recognizes OAuth tokens' do
@@ -29,7 +29,7 @@ describe Gitlab::Auth, lib: true do
       ip = 'ip'
 
       expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'oauth2')
-      expect(gl_auth.find("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, :oauth))
+      expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, :oauth))
     end
 
     it 'returns double nil for invalid credentials' do
@@ -37,11 +37,11 @@ describe Gitlab::Auth, lib: true do
       ip = 'ip'
 
       expect(gl_auth).to receive(:rate_limit!).with(ip, success: false, login: login)
-      expect(gl_auth.find(login, 'bar', project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new)
+      expect(gl_auth.find_for_git_client(login, 'bar', project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new)
     end
   end
 
-  describe 'find_in_gitlab_or_ldap' do
+  describe 'find_with_user_password' do
     let!(:user) do
       create(:user,
         username: username,
@@ -52,25 +52,25 @@ describe Gitlab::Auth, lib: true do
     let(:password) { 'my-secret' }
 
     it "should find user by valid login/password" do
-      expect( gl_auth.find_in_gitlab_or_ldap(username, password) ).to eql user
+      expect( gl_auth.find_with_user_password(username, password) ).to eql user
     end
 
     it 'should find user by valid email/password with case-insensitive email' do
-      expect(gl_auth.find_in_gitlab_or_ldap(user.email.upcase, password)).to eql user
+      expect(gl_auth.find_with_user_password(user.email.upcase, password)).to eql user
     end
 
     it 'should find user by valid username/password with case-insensitive username' do
-      expect(gl_auth.find_in_gitlab_or_ldap(username.upcase, password)).to eql user
+      expect(gl_auth.find_with_user_password(username.upcase, password)).to eql user
     end
 
     it "should not find user with invalid password" do
       password = 'wrong'
-      expect( gl_auth.find_in_gitlab_or_ldap(username, password) ).not_to eql user
+      expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
     end
 
     it "should not find user with invalid login" do
       user = 'wrong'
-      expect( gl_auth.find_in_gitlab_or_ldap(username, password) ).not_to eql user
+      expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
     end
 
     context "with ldap enabled" do
@@ -81,13 +81,13 @@ describe Gitlab::Auth, lib: true do
       it "tries to autheticate with db before ldap" do
         expect(Gitlab::LDAP::Authentication).not_to receive(:login)
 
-        gl_auth.find_in_gitlab_or_ldap(username, password)
+        gl_auth.find_with_user_password(username, password)
       end
 
       it "uses ldap as fallback to for authentication" do
         expect(Gitlab::LDAP::Authentication).to receive(:login)
 
-        gl_auth.find_in_gitlab_or_ldap('ldap_user', 'password')
+        gl_auth.find_with_user_password('ldap_user', 'password')
       end
     end
   end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index db0ff95b4f5c6c83be75122b2ad560f05dea14a4..270b89972d73d1a452e37152085810c84ea151c6 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -43,6 +43,18 @@ describe Gitlab::ProjectSearchResults, lib: true do
       expect(results.issues_count).to eq 1
     end
 
+    it 'should not list project confidential issues for project members with guest role' do
+      project.team << [member, :guest]
+
+      results = described_class.new(member, project, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).not_to include security_issue_1
+      expect(issues).not_to include security_issue_2
+      expect(results.issues_count).to eq 1
+    end
+
     it 'should list project confidential issues for author' do
       results = described_class.new(author, project, query)
       issues = results.objects('issues')
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index f4afe597e8d8c415c40b5f3bc48c2e00ac3be71f..1bb444bf34fc2101d67e6b9e2c4ce6a5bc3fb0bc 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -86,6 +86,22 @@ describe Gitlab::SearchResults do
       expect(results.issues_count).to eq 1
     end
 
+    it 'should not list confidential issues for project members with guest role' do
+      project_1.team << [member, :guest]
+      project_2.team << [member, :guest]
+
+      results = described_class.new(member, limit_projects, query)
+      issues = results.objects('issues')
+
+      expect(issues).to include issue
+      expect(issues).not_to include security_issue_1
+      expect(issues).not_to include security_issue_2
+      expect(issues).not_to include security_issue_3
+      expect(issues).not_to include security_issue_4
+      expect(issues).not_to include security_issue_5
+      expect(results.issues_count).to eq 1
+    end
+
     it 'should list confidential issues for author' do
       results = described_class.new(author, limit_projects, query)
       issues = results.objects('issues')
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
index 47c3be673c56815d3828be81793f5c2fe9f87303..7e9ab8940cfa112792d1ec13b320c54f8578dce7 100644
--- a/spec/models/concerns/milestoneish_spec.rb
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -5,6 +5,7 @@ describe Milestone, 'Milestoneish' do
   let(:assignee) { create(:user) }
   let(:non_member) { create(:user) }
   let(:member) { create(:user) }
+  let(:guest) { create(:user) }
   let(:admin) { create(:admin) }
   let(:project) { create(:project, :public) }
   let(:milestone) { create(:milestone, project: project) }
@@ -21,6 +22,7 @@ describe Milestone, 'Milestoneish' do
 
   before do
     project.team << [member, :developer]
+    project.team << [guest, :guest]
   end
 
   describe '#closed_items_count' do
@@ -28,6 +30,10 @@ describe Milestone, 'Milestoneish' do
       expect(milestone.closed_items_count(non_member)).to eq 2
     end
 
+    it 'should not count confidential issues for project members with guest role' do
+      expect(milestone.closed_items_count(guest)).to eq 2
+    end
+
     it 'should count confidential issues for author' do
       expect(milestone.closed_items_count(author)).to eq 4
     end
@@ -50,6 +56,10 @@ describe Milestone, 'Milestoneish' do
       expect(milestone.total_items_count(non_member)).to eq 4
     end
 
+    it 'should not count confidential issues for project members with guest role' do
+      expect(milestone.total_items_count(guest)).to eq 4
+    end
+
     it 'should count confidential issues for author' do
       expect(milestone.total_items_count(author)).to eq 7
     end
@@ -85,6 +95,10 @@ describe Milestone, 'Milestoneish' do
       expect(milestone.percent_complete(non_member)).to eq 50
     end
 
+    it 'should not count confidential issues for project members with guest role' do
+      expect(milestone.percent_complete(guest)).to eq 50
+    end
+
     it 'should count confidential issues for author' do
       expect(milestone.percent_complete(author)).to eq 57
     end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index b0e76fec6935cbea12ce9d26756832e7c325cf28..166a1dc4ddb52a2f75c6a19cc2dc94b579f44503 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -50,6 +50,7 @@ describe Event, models: true do
     let(:project) { create(:empty_project, :public) }
     let(:non_member) { create(:user) }
     let(:member)  { create(:user) }
+    let(:guest)  { create(:user) }
     let(:author) { create(:author) }
     let(:assignee) { create(:user) }
     let(:admin) { create(:admin) }
@@ -61,6 +62,7 @@ describe Event, models: true do
 
     before do
       project.team << [member, :developer]
+      project.team << [guest, :guest]
     end
 
     context 'issue event' do
@@ -71,6 +73,7 @@ describe Event, models: true do
         it { expect(event.visible_to_user?(author)).to eq true }
         it { expect(event.visible_to_user?(assignee)).to eq true }
         it { expect(event.visible_to_user?(member)).to eq true }
+        it { expect(event.visible_to_user?(guest)).to eq true }
         it { expect(event.visible_to_user?(admin)).to eq true }
       end
 
@@ -81,6 +84,7 @@ describe Event, models: true do
         it { expect(event.visible_to_user?(author)).to eq true }
         it { expect(event.visible_to_user?(assignee)).to eq true }
         it { expect(event.visible_to_user?(member)).to eq true }
+        it { expect(event.visible_to_user?(guest)).to eq false }
         it { expect(event.visible_to_user?(admin)).to eq true }
       end
     end
@@ -93,6 +97,7 @@ describe Event, models: true do
         it { expect(event.visible_to_user?(author)).to eq true }
         it { expect(event.visible_to_user?(assignee)).to eq true }
         it { expect(event.visible_to_user?(member)).to eq true }
+        it { expect(event.visible_to_user?(guest)).to eq true }
         it { expect(event.visible_to_user?(admin)).to eq true }
       end
 
@@ -103,6 +108,7 @@ describe Event, models: true do
         it { expect(event.visible_to_user?(author)).to eq true }
         it { expect(event.visible_to_user?(assignee)).to eq true }
         it { expect(event.visible_to_user?(member)).to eq true }
+        it { expect(event.visible_to_user?(guest)).to eq false }
         it { expect(event.visible_to_user?(admin)).to eq true }
       end
     end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index f15e96714b2d69096a35c90f1c48e2cc22ab3394..285ab19cfafd9d93526ff1193bd229637b456a27 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -162,16 +162,23 @@ describe Note, models: true do
     end
 
     context "confidential issues" do
-      let(:user) { create :user }
-      let(:confidential_issue) { create(:issue, :confidential, author: user) }
-      let(:confidential_note) { create :note, note: "Random", noteable: confidential_issue, project: confidential_issue.project }
+      let(:user) { create(:user) }
+      let(:project) { create(:project) }
+      let(:confidential_issue) { create(:issue, :confidential, project: project, author: user) }
+      let(:confidential_note) { create(:note, note: "Random", noteable: confidential_issue, project: confidential_issue.project) }
 
       it "returns notes with matching content if user can see the issue" do
         expect(described_class.search(confidential_note.note, as_user: user)).to eq([confidential_note])
       end
 
       it "does not return notes with matching content if user can not see the issue" do
-        user = create :user
+        user = create(:user)
+        expect(described_class.search(confidential_note.note, as_user: user)).to be_empty
+      end
+
+      it "does not return notes with matching content for project members with guest role" do
+        user = create(:user)
+        project.team << [user, :guest]
         expect(described_class.search(confidential_note.note, as_user: user)).to be_empty
       end
 
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index ec81f05fc7a075b714d005bfdbd0ea498763ef2d..9ae461f8c2d8befbb6042a3b49fec7aeb455e0f9 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -126,25 +126,25 @@ describe BambooService, models: true do
     it 'returns a specific URL when status is 500' do
       stub_request(status: 500)
 
-      expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/browse/foo')
+      expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/bamboo/browse/foo')
     end
 
     it 'returns a specific URL when response has no results' do
       stub_request(body: %Q({"results":{"results":{"size":"0"}}}))
 
-      expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/browse/foo')
+      expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/bamboo/browse/foo')
     end
 
     it 'returns a build URL when bamboo_url has no trailing slash' do
       stub_request(body: %Q({"results":{"results":{"result":{"planResultKey":{"key":"42"}}}}}))
 
-      expect(service(bamboo_url: 'http://gitlab.com').build_page('123', 'unused')).to eq('http://gitlab.com/browse/42')
+      expect(service(bamboo_url: 'http://gitlab.com/bamboo').build_page('123', 'unused')).to eq('http://gitlab.com/bamboo/browse/42')
     end
 
     it 'returns a build URL when bamboo_url has a trailing slash' do
       stub_request(body: %Q({"results":{"results":{"result":{"planResultKey":{"key":"42"}}}}}))
 
-      expect(service(bamboo_url: 'http://gitlab.com/').build_page('123', 'unused')).to eq('http://gitlab.com/browse/42')
+      expect(service(bamboo_url: 'http://gitlab.com/bamboo/').build_page('123', 'unused')).to eq('http://gitlab.com/bamboo/browse/42')
     end
   end
 
@@ -192,7 +192,7 @@ describe BambooService, models: true do
     end
   end
 
-  def service(bamboo_url: 'http://gitlab.com')
+  def service(bamboo_url: 'http://gitlab.com/bamboo')
     described_class.create(
       project: create(:empty_project),
       properties: {
@@ -205,7 +205,7 @@ describe BambooService, models: true do
   end
 
   def stub_request(status: 200, body: nil, build_state: 'success')
-    bamboo_full_url = 'http://mic:password@gitlab.com/rest/api/latest/result?label=123&os_authType=basic'
+    bamboo_full_url = 'http://mic:password@gitlab.com/bamboo/rest/api/latest/result?label=123&os_authType=basic'
     body ||= %Q({"results":{"results":{"result":{"buildState":"#{build_state}"}}}})
 
     WebMock.stub_request(:get, bamboo_full_url).to_return(
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index 24a708ca849e9d96d0ae75f59b01fd486217aa61..474715d24c3adbcd7cde80b017bba2aa72d9f5b5 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -126,19 +126,19 @@ describe TeamcityService, models: true do
     it 'returns a specific URL when status is 500' do
       stub_request(status: 500)
 
-      expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/viewLog.html?buildTypeId=foo')
+      expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/teamcity/viewLog.html?buildTypeId=foo')
     end
 
     it 'returns a build URL when teamcity_url has no trailing slash' do
       stub_request(body: %Q({"build":{"id":"666"}}))
 
-      expect(service(teamcity_url: 'http://gitlab.com').build_page('123', 'unused')).to eq('http://gitlab.com/viewLog.html?buildId=666&buildTypeId=foo')
+      expect(service(teamcity_url: 'http://gitlab.com/teamcity').build_page('123', 'unused')).to eq('http://gitlab.com/teamcity/viewLog.html?buildId=666&buildTypeId=foo')
     end
 
     it 'returns a build URL when teamcity_url has a trailing slash' do
       stub_request(body: %Q({"build":{"id":"666"}}))
 
-      expect(service(teamcity_url: 'http://gitlab.com/').build_page('123', 'unused')).to eq('http://gitlab.com/viewLog.html?buildId=666&buildTypeId=foo')
+      expect(service(teamcity_url: 'http://gitlab.com/teamcity/').build_page('123', 'unused')).to eq('http://gitlab.com/teamcity/viewLog.html?buildId=666&buildTypeId=foo')
     end
   end
 
@@ -180,7 +180,7 @@ describe TeamcityService, models: true do
     end
   end
 
-  def service(teamcity_url: 'http://gitlab.com')
+  def service(teamcity_url: 'http://gitlab.com/teamcity')
     described_class.create(
       project: create(:empty_project),
       properties: {
@@ -193,7 +193,7 @@ describe TeamcityService, models: true do
   end
 
   def stub_request(status: 200, body: nil, build_status: 'success')
-    teamcity_full_url = 'http://mic:password@gitlab.com/httpAuth/app/rest/builds/branch:unspecified:any,number:123'
+    teamcity_full_url = 'http://mic:password@gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,number:123'
     body ||= %Q({"build":{"status":"#{build_status}","id":"666"}})
 
     WebMock.stub_request(:get, teamcity_full_url).to_return(
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f3590f72cfeb0dd8ceced01eb187206fecfa2756..de8815f5a38271560ccf24602e7562edc477715c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -53,7 +53,6 @@ describe Project, models: true do
     it { is_expected.to validate_length_of(:path).is_within(0..255) }
     it { is_expected.to validate_length_of(:description).is_within(0..2000) }
     it { is_expected.to validate_presence_of(:creator) }
-    it { is_expected.to validate_length_of(:issues_tracker_id).is_within(0..255) }
     it { is_expected.to validate_presence_of(:namespace) }
 
     it 'should not allow new projects beyond user limits' do
@@ -321,27 +320,6 @@ describe Project, models: true do
     end
   end
 
-  describe :can_have_issues_tracker_id? do
-    let(:project) { create(:project) }
-    let(:ext_project) { create(:redmine_project) }
-
-    it 'should be true for projects with external issues tracker if issues enabled' do
-      expect(ext_project.can_have_issues_tracker_id?).to be_truthy
-    end
-
-    it 'should be false for projects with internal issue tracker if issues enabled' do
-      expect(project.can_have_issues_tracker_id?).to be_falsey
-    end
-
-    it 'should be always false if issues disabled' do
-      project.issues_enabled = false
-      ext_project.issues_enabled = false
-
-      expect(project.can_have_issues_tracker_id?).to be_falsey
-      expect(ext_project.can_have_issues_tracker_id?).to be_falsey
-    end
-  end
-
   describe :open_branches do
     let(:project) { create(:project) }
 
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index bacb17a8883646a8ffefb2f899b1d83efbbfafc3..8bebd6a944721de4fa468e25df124bbd18a3f57f 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -29,6 +29,9 @@ describe ProjectTeam, models: true do
       it { expect(project.team.master?(nonmember)).to be_falsey }
       it { expect(project.team.member?(nonmember)).to be_falsey }
       it { expect(project.team.member?(guest)).to be_truthy }
+      it { expect(project.team.member?(reporter, Gitlab::Access::REPORTER)).to be_truthy }
+      it { expect(project.team.member?(guest, Gitlab::Access::REPORTER)).to be_falsey }
+      it { expect(project.team.member?(nonmember, Gitlab::Access::GUEST)).to be_falsey }
     end
   end
 
@@ -64,6 +67,9 @@ describe ProjectTeam, models: true do
       it { expect(project.team.master?(nonmember)).to be_falsey }
       it { expect(project.team.member?(nonmember)).to be_falsey }
       it { expect(project.team.member?(guest)).to be_truthy }
+      it { expect(project.team.member?(guest, Gitlab::Access::MASTER)).to be_truthy }
+      it { expect(project.team.member?(reporter, Gitlab::Access::MASTER)).to be_falsey }
+      it { expect(project.team.member?(nonmember, Gitlab::Access::GUEST)).to be_falsey }
     end
   end
 
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index bb9261725932ac67bdd06332790b1f4a1ee10d6a..59e557c5b2a21d3c25359462fc947c7408bffc6e 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -5,6 +5,7 @@ describe API::API, api: true  do
   let(:user)        { create(:user) }
   let(:user2)       { create(:user) }
   let(:non_member)  { create(:user) }
+  let(:guest)       { create(:user) }
   let(:author)      { create(:author) }
   let(:assignee)    { create(:assignee) }
   let(:admin)       { create(:user, :admin) }
@@ -41,7 +42,10 @@ describe API::API, api: true  do
   end
   let!(:note) { create(:note_on_issue, author: user, project: project, noteable: issue) }
 
-  before { project.team << [user, :reporter] }
+  before do
+    project.team << [user, :reporter]
+    project.team << [guest, :guest]
+  end
 
   describe "GET /issues" do
     context "when unauthenticated" do
@@ -144,6 +148,14 @@ describe API::API, api: true  do
       expect(json_response.first['title']).to eq(issue.title)
     end
 
+    it 'should return project issues without confidential issues for project members with guest role' do
+      get api("#{base_url}/issues", guest)
+      expect(response.status).to eq(200)
+      expect(json_response).to be_an Array
+      expect(json_response.length).to eq(2)
+      expect(json_response.first['title']).to eq(issue.title)
+    end
+
     it 'should return project confidential issues for author' do
       get api("#{base_url}/issues", author)
       expect(response.status).to eq(200)
@@ -278,6 +290,11 @@ describe API::API, api: true  do
         expect(response.status).to eq(404)
       end
 
+      it "should return 404 for project members with guest role" do
+        get api("/projects/#{project.id}/issues/#{confidential_issue.id}", guest)
+        expect(response.status).to eq(404)
+      end
+
       it "should return confidential issue for project members" do
         get api("/projects/#{project.id}/issues/#{confidential_issue.id}", user)
         expect(response.status).to eq(200)
@@ -413,6 +430,12 @@ describe API::API, api: true  do
         expect(response.status).to eq(403)
       end
 
+      it "should return 403 for project members with guest role" do
+        put api("/projects/#{project.id}/issues/#{confidential_issue.id}", guest),
+          title: 'updated title'
+        expect(response.status).to eq(403)
+      end
+
       it "should update a confidential issue for project members" do
         put api("/projects/#{project.id}/issues/#{confidential_issue.id}", user),
           title: 'updated title'
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 241995041bb113828eac54c99efb9dd4e512f578..0154d1c62cc02f4bd9661d4907e1c3435bc13234 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -146,6 +146,7 @@ describe API::API, api: true  do
       let(:milestone) { create(:milestone, project: public_project) }
       let(:issue) { create(:issue, project: public_project) }
       let(:confidential_issue) { create(:issue, confidential: true, project: public_project) }
+
       before do
         public_project.team << [user, :developer]
         milestone.issues << issue << confidential_issue
@@ -160,6 +161,18 @@ describe API::API, api: true  do
         expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id)
       end
 
+      it 'does not return confidential issues to team members with guest role' do
+        member = create(:user)
+        project.team << [member, :guest]
+
+        get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", member)
+
+        expect(response.status).to eq(200)
+        expect(json_response).to be_an Array
+        expect(json_response.size).to eq(1)
+        expect(json_response.map { |issue| issue['id'] }).to include(issue.id)
+      end
+
       it 'does not return confidential issues to regular users' do
         get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", create(:user))
 
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index c995993a8531e15aaad4e84064f060cfcc6ef5e0..d2d4a9eca18faded89a085ce5c033570b760de7e 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -44,7 +44,7 @@ describe JwtController do
       let(:user) { create(:user) }
       let(:headers) { { authorization: credentials('user', 'password') } }
 
-      before { expect(Gitlab::Auth).to receive(:find_in_gitlab_or_ldap).with('user', 'password').and_return(user) }
+      before { expect(Gitlab::Auth).to receive(:find_with_user_password).with('user', 'password').and_return(user) }
 
       subject! { get '/jwt/auth', parameters, headers }
 
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index b99e02ba67855a33bcc395cf9df4d9ff6224961d..e871a103d42a96b3b513c072af434da80090b2eb 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -132,12 +132,14 @@ describe NotificationService, services: true do
       let(:assignee) { create(:user) }
       let(:non_member) { create(:user) }
       let(:member) { create(:user) }
+      let(:guest) { create(:user) }
       let(:admin) { create(:admin) }
       let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee) }
       let(:note) { create(:note_on_issue, noteable: confidential_issue, project: project, note: "#{author.to_reference} #{assignee.to_reference} #{non_member.to_reference} #{member.to_reference} #{admin.to_reference}") }
 
       it 'filters out users that can not read the issue' do
         project.team << [member, :developer]
+        project.team << [guest, :guest]
 
         expect(SentNotification).to receive(:record).with(confidential_issue, any_args).exactly(4).times
 
@@ -146,6 +148,7 @@ describe NotificationService, services: true do
         notification.new_note(note)
 
         should_not_email(non_member)
+        should_not_email(guest)
         should_email(author)
         should_email(assignee)
         should_email(member)
@@ -322,17 +325,20 @@ describe NotificationService, services: true do
         let(:assignee) { create(:user) }
         let(:non_member) { create(:user) }
         let(:member) { create(:user) }
+        let(:guest) { create(:user) }
         let(:admin) { create(:admin) }
         let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignee: assignee) }
 
         it "emails subscribers of the issue's labels that can read the issue" do
           project.team << [member, :developer]
+          project.team << [guest, :guest]
 
           label = create(:label, issues: [confidential_issue])
           label.toggle_subscription(non_member)
           label.toggle_subscription(author)
           label.toggle_subscription(assignee)
           label.toggle_subscription(member)
+          label.toggle_subscription(guest)
           label.toggle_subscription(admin)
 
           ActionMailer::Base.deliveries.clear
@@ -341,6 +347,7 @@ describe NotificationService, services: true do
 
           should_not_email(non_member)
           should_not_email(author)
+          should_not_email(guest)
           should_email(assignee)
           should_email(member)
           should_email(admin)
@@ -490,6 +497,7 @@ describe NotificationService, services: true do
         let(:assignee) { create(:user) }
         let(:non_member) { create(:user) }
         let(:member) { create(:user) }
+        let(:guest) { create(:user) }
         let(:admin) { create(:admin) }
         let(:confidential_issue) { create(:issue, :confidential, project: project, title: 'Confidential issue', author: author, assignee: assignee) }
         let!(:label_1) { create(:label, issues: [confidential_issue]) }
@@ -497,11 +505,13 @@ describe NotificationService, services: true do
 
         it "emails subscribers of the issue's labels that can read the issue" do
           project.team << [member, :developer]
+          project.team << [guest, :guest]
 
           label_2.toggle_subscription(non_member)
           label_2.toggle_subscription(author)
           label_2.toggle_subscription(assignee)
           label_2.toggle_subscription(member)
+          label_2.toggle_subscription(guest)
           label_2.toggle_subscription(admin)
 
           ActionMailer::Base.deliveries.clear
@@ -509,6 +519,7 @@ describe NotificationService, services: true do
           notification.relabeled_issue(confidential_issue, [label_2], @u_disabled)
 
           should_not_email(non_member)
+          should_not_email(guest)
           should_email(author)
           should_email(assignee)
           should_email(member)
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
index 6108c26a78b862808dacd7b9b1d80e6757df8f5f..0971fec2e9f29bf9a34d11c7bcf27e1ba181b6b7 100644
--- a/spec/services/projects/autocomplete_service_spec.rb
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -33,6 +33,18 @@ describe Projects::AutocompleteService, services: true do
         expect(issues.count).to eq 1
       end
 
+      it 'should not list project confidential issues for project members with guest role' do
+        project.team << [member, :guest]
+
+        autocomplete = described_class.new(project, non_member)
+        issues = autocomplete.issues.map(&:iid)
+
+        expect(issues).to include issue.iid
+        expect(issues).not_to include security_issue_1.iid
+        expect(issues).not_to include security_issue_2.iid
+        expect(issues.count).to eq 1
+      end
+
       it 'should list project confidential issues for author' do
         autocomplete = described_class.new(project, author)
         issues = autocomplete.issues.map(&:iid)
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 489c920f19fb6ff805fcdb1edaf76d173eaf1cc6..549a936b060ff9270165b82b6734b30a8bfed2e3 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -5,13 +5,15 @@ describe TodoService, services: true do
   let(:assignee) { create(:user) }
   let(:non_member) { create(:user) }
   let(:member) { create(:user) }
+  let(:guest) { create(:user) }
   let(:admin) { create(:admin) }
   let(:john_doe) { create(:user) }
   let(:project) { create(:project) }
-  let(:mentions) { [author, assignee, john_doe, member, non_member, admin].map(&:to_reference).join(' ') }
+  let(:mentions) { [author, assignee, john_doe, member, guest, non_member, admin].map(&:to_reference).join(' ') }
   let(:service) { described_class.new }
 
   before do
+    project.team << [guest, :guest]
     project.team << [author, :developer]
     project.team << [member, :developer]
     project.team << [john_doe, :developer]
@@ -41,18 +43,20 @@ describe TodoService, services: true do
         service.new_issue(issue, author)
 
         should_create_todo(user: member, target: issue, action: Todo::MENTIONED)
+        should_create_todo(user: guest, target: issue, action: Todo::MENTIONED)
         should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED)
         should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
         should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
       end
 
-      it 'does not create todo for non project members when issue is confidential' do
+      it 'does not create todo if user can not see the issue when issue is confidential' do
         service.new_issue(confidential_issue, john_doe)
 
         should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::ASSIGNED)
         should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
+        should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
       end
 
@@ -81,6 +85,7 @@ describe TodoService, services: true do
         service.update_issue(issue, author)
 
         should_create_todo(user: member, target: issue, action: Todo::MENTIONED)
+        should_create_todo(user: guest, target: issue, action: Todo::MENTIONED)
         should_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
         should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED)
         should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
@@ -92,13 +97,14 @@ describe TodoService, services: true do
         expect { service.update_issue(issue, author) }.not_to change(member.todos, :count)
       end
 
-      it 'does not create todo for non project members when issue is confidential' do
+      it 'does not create todo if user can not see the issue when issue is confidential' do
         service.update_issue(confidential_issue, john_doe)
 
         should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
+        should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
         should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
       end
 
@@ -192,18 +198,20 @@ describe TodoService, services: true do
         service.new_note(note, john_doe)
 
         should_create_todo(user: member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
+        should_create_todo(user: guest, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
         should_create_todo(user: author, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
         should_not_create_todo(user: john_doe, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
         should_not_create_todo(user: non_member, target: issue, author: john_doe, action: Todo::MENTIONED, note: note)
       end
 
-      it 'does not create todo for non project members when leaving a note on a confidential issue' do
+      it 'does not create todo if user can not see the issue when leaving a note on a confidential issue' do
         service.new_note(note_on_confidential_issue, john_doe)
 
         should_create_todo(user: author, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
         should_create_todo(user: assignee, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
         should_create_todo(user: member, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
         should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
+        should_not_create_todo(user: guest, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
         should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED, note: note_on_confidential_issue)
       end
 
@@ -245,6 +253,7 @@ describe TodoService, services: true do
         service.new_merge_request(mr_assigned, author)
 
         should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
+        should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
         should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
         should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
         should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)
@@ -256,6 +265,7 @@ describe TodoService, services: true do
         service.update_merge_request(mr_assigned, author)
 
         should_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
+        should_create_todo(user: guest, target: mr_assigned, action: Todo::MENTIONED)
         should_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
         should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
         should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)