From 377b59da3029786f2265058972ad0bc6aefd8b53 Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Tue, 12 Apr 2016 09:59:01 +0530
Subject: [PATCH 1/9] Sanitize branch names for confidential issues.

- When creating new branches for confidential issues,
  prefer a branch name like `issue-15` to
  `some-sensitive-issue-title-15`.
- The behaviour for non-confidential issues stays the same.
---
 app/models/issue.rb | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/app/models/issue.rb b/app/models/issue.rb
index e064b0f8b95..68e0113380e 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -151,7 +151,11 @@ class Issue < ActiveRecord::Base
   end
 
   def to_branch_name
-    "#{title.parameterize}-#{iid}"
+    if self.confidential?
+      "issue-#{iid}"
+    else
+      "#{title.parameterize}-#{iid}"
+    end
   end
 
   def can_be_worked_on?(current_user)
-- 
GitLab


From 5d88de092f37497d9c08878954b099c425376bda Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Tue, 12 Apr 2016 11:43:15 +0530
Subject: [PATCH 2/9] Refactor `Issue#related_branches`

- Previously, the controller held the logic to calculate
  related branches, which was:

  `<branches ending with `issue.iid`> - <branches with a merge request referenced in the current issue>`

- This logic belongs in the `related_branches` method, not in the
  controller. This commit makes this change.

- This means that `Issue#related_branches` now needs to take a `User`.
  When we find the branches that have a merge request referenced in the
  current issue, this is limited to merge requests that the current user
  has access to.

- This is not directly related to #14566, but is a related refactoring.
---
 app/controllers/projects/issues_controller.rb |  2 +-
 app/models/issue.rb                           | 13 ++++++++++---
 spec/models/issue_spec.rb                     |  3 ++-
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 6d649e72f84..a3842036982 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -66,7 +66,7 @@ class Projects::IssuesController < Projects::ApplicationController
     @notes = @issue.notes.nonawards.with_associations.fresh
     @noteable = @issue
     @merge_requests = @issue.referenced_merge_requests(current_user)
-    @related_branches = @issue.related_branches - @merge_requests.map(&:source_branch)
+    @related_branches = @issue.related_branches(current_user)
 
     respond_to do |format|
       format.html
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 68e0113380e..252545d1147 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -104,10 +104,17 @@ class Issue < ActiveRecord::Base
     end
   end
 
-  def related_branches
-    project.repository.branch_names.select do |branch|
+  # All branches containing the current issue's ID, except for
+  # those with a merge request open (that the current user can see)
+  # referencing the current issue.
+  def related_branches(current_user)
+    branches_with_iid = project.repository.branch_names.select do |branch|
       branch.end_with?("-#{iid}")
     end
+
+    branches_with_merge_request = self.referenced_merge_requests(current_user).map(&:source_branch)
+
+    branches_with_iid - branches_with_merge_request
   end
 
   # Reset issue events cache
@@ -161,7 +168,7 @@ class Issue < ActiveRecord::Base
   def can_be_worked_on?(current_user)
     !self.closed? &&
       !self.project.forked? &&
-      self.related_branches.empty? &&
+      self.related_branches(current_user).empty? &&
       self.closed_by_merge_requests(current_user).empty?
   end
 end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 15052aaca28..f33b705810e 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -192,10 +192,11 @@ describe Issue, models: true do
 
   describe '#related_branches' do
     it "selects the right branches" do
+      user = build(:user)
       allow(subject.project.repository).to receive(:branch_names).
         and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name])
 
-      expect(subject.related_branches).to eq([subject.to_branch_name])
+      expect(subject.related_branches(user)).to eq([subject.to_branch_name])
     end
   end
 
-- 
GitLab


From 91034af3c998ce4a4f83281525304e8c50add384 Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Tue, 12 Apr 2016 15:50:19 +0530
Subject: [PATCH 3/9] Augment the tests for `Issue#related_branches`

- Test the case where we have a referenced merge request that's being
- excluded as a "related branch"
- This took a while to figure out, especially the
  `create_cross_references!` line.
---
 spec/models/issue_spec.rb | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index f33b705810e..8cacce6a7bf 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -191,11 +191,27 @@ describe Issue, models: true do
   end
 
   describe '#related_branches' do
-    it "selects the right branches" do
-      user = build(:user)
+    let(:user) { build(:user, :admin) }
+    let(:merge_request) { create(:merge_request, description: "Closes ##{subject.iid}",
+                                 source_project: subject.project, source_branch: "branch-#{subject.iid}") }
+
+    before(:each) do
       allow(subject.project.repository).to receive(:branch_names).
-        and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name])
+                                            and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name, "branch-#{subject.iid}"])
+
+      # Without this stub, the `create(:merge_request)` above fails because it can't find
+      # the source branch. This seems like a reasonable compromise, in comparison with
+      # setting up a full repo here.
+      allow_any_instance_of(MergeRequest).to receive(:create_merge_request_diff)
+    end
+
+    it "selects the right branches when there are no referenced merge requests" do
+      expect(subject.related_branches(user)).to eq([subject.to_branch_name, "branch-#{subject.iid}"])
+    end
 
+    it "selects the right branches when there is a referenced merge request" do
+      merge_request.create_cross_references!(user)
+      expect(subject.referenced_merge_requests).to_not be_empty
       expect(subject.related_branches(user)).to eq([subject.to_branch_name])
     end
   end
-- 
GitLab


From 66ca80181bcb5aef97296fde567b899603186be6 Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Tue, 12 Apr 2016 16:01:44 +0530
Subject: [PATCH 4/9] Test the `Issue#to_branch_name` method.

---
 spec/models/issue_spec.rb | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 8cacce6a7bf..22dabaa0404 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -228,10 +228,19 @@ describe Issue, models: true do
   end
 
   describe "#to_branch_name" do
-    let(:issue) { create(:issue, title: 'a' * 30) }
+    let(:issue) { create(:issue, title: 'testing-issue') }
 
-    it "starts with the issue iid" do
+    it "ends with the issue iid" do
       expect(issue.to_branch_name).to match /-#{issue.iid}\z/
     end
+
+    it "contains the issue title if not confidential" do
+      expect(issue.to_branch_name).to match /\Atesting-issue/
+    end
+
+    it "does not contain the issue title if confidential" do
+      issue = create(:issue, title: 'testing-issue', confidential: true)
+      expect(issue.to_branch_name).to match /\Aissue/
+    end
   end
 end
-- 
GitLab


From 8dd1a6fc917231e83fb64dbfa65e1edbe9ab3fee Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Wed, 13 Apr 2016 09:04:08 +0530
Subject: [PATCH 5/9] Fix the rubocop check.

---
 spec/models/issue_spec.rb | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 22dabaa0404..202ce846dca 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -192,8 +192,6 @@ describe Issue, models: true do
 
   describe '#related_branches' do
     let(:user) { build(:user, :admin) }
-    let(:merge_request) { create(:merge_request, description: "Closes ##{subject.iid}",
-                                 source_project: subject.project, source_branch: "branch-#{subject.iid}") }
 
     before(:each) do
       allow(subject.project.repository).to receive(:branch_names).
@@ -210,6 +208,9 @@ describe Issue, models: true do
     end
 
     it "selects the right branches when there is a referenced merge request" do
+      merge_request = create(:merge_request, { description: "Closes ##{subject.iid}",
+                                               source_project: subject.project,
+                                               source_branch: "branch-#{subject.iid}" })
       merge_request.create_cross_references!(user)
       expect(subject.referenced_merge_requests).to_not be_empty
       expect(subject.related_branches(user)).to eq([subject.to_branch_name])
-- 
GitLab


From 769a8bf7284da492732d923cb888c0f5be16aff8 Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Wed, 13 Apr 2016 09:18:29 +0530
Subject: [PATCH 6/9] Update CHANGELOG

---
 CHANGELOG | 1 +
 1 file changed, 1 insertion(+)

diff --git a/CHANGELOG b/CHANGELOG
index 3561c541df0..738162d983f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -34,6 +34,7 @@ v 8.7.0 (unreleased)
   - API: Expose user location (Robert Schilling)
   - ClosingIssueExtractor regex now also works with colons. e.g. "Fixes: #1234" !3591
   - Update number of Todos in the sidebar when it's marked as "Done". !3600
+  - Sanitize branch names created for confidential issues
 
 v 8.6.5
   - Fix importing from GitHub Enterprise. !3529
-- 
GitLab


From f5ce601c2b052b18398d2207c64ce8828b628521 Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Fri, 15 Apr 2016 09:31:26 +0530
Subject: [PATCH 7/9] Make a few style changes based on MR feedback.

---
 spec/models/issue_spec.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 202ce846dca..ed982d8a9d4 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -191,9 +191,9 @@ describe Issue, models: true do
   end
 
   describe '#related_branches' do
-    let(:user) { build(:user, :admin) }
+    let(:user) { build(:admin) }
 
-    before(:each) do
+    before do
       allow(subject.project.repository).to receive(:branch_names).
                                             and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name, "branch-#{subject.iid}"])
 
-- 
GitLab


From aa396ae5ee5715c1a2a8a82731cef6e3d7f73056 Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Mon, 18 Apr 2016 13:01:23 +0530
Subject: [PATCH 8/9] Remove unused variable in `IssuesController`.

---
 app/controllers/projects/issues_controller.rb | 2 --
 1 file changed, 2 deletions(-)

diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index f3056b21007..f2ae572cfe1 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -128,8 +128,6 @@ class Projects::IssuesController < Projects::ApplicationController
   end
 
   def related_branches
-    merge_requests = @issue.referenced_merge_requests(current_user)
-
     @related_branches = @issue.related_branches(current_user)
 
     respond_to do |format|
-- 
GitLab


From f801e2243dcce6d3bdce01acf62fbf5a49a301da Mon Sep 17 00:00:00 2001
From: Timothy Andrew <mail@timothyandrew.net>
Date: Tue, 19 Apr 2016 09:22:55 +0530
Subject: [PATCH 9/9] A new branch created for a confidential issue is named
 `<id>-confidential-issue`.

---
 app/models/issue.rb       | 2 +-
 spec/models/issue_spec.rb | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/models/issue.rb b/app/models/issue.rb
index 530d2107596..2f773869603 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -158,7 +158,7 @@ class Issue < ActiveRecord::Base
 
   def to_branch_name
     if self.confidential?
-      "issue-#{iid}"
+      "#{iid}-confidential-issue"
     else
       "#{iid}-#{title.parameterize}"
     end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index da1c673653a..060e6599104 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -248,7 +248,7 @@ describe Issue, models: true do
 
     it "does not contain the issue title if confidential" do
       issue = create(:issue, title: 'testing-issue', confidential: true)
-      expect(issue.to_branch_name).to match /\Aissue/
+      expect(issue.to_branch_name).to match /confidential-issue\z/
     end
   end
 end
-- 
GitLab