diff --git a/debian/patches/CVE-2019-19254.patch b/debian/patches/CVE-2019-19254.patch new file mode 100644 index 0000000000..b702cb914e --- /dev/null +++ b/debian/patches/CVE-2019-19254.patch @@ -0,0 +1,134 @@ +From 879ca8ab319a60f114e99a57848467d252fc65c7 Mon Sep 17 00:00:00 2001 +From: Aakriti Gupta +Date: Wed, 6 Nov 2019 17:07:11 +0100 +Subject: [PATCH] Prevent guests from seeing commits for cycle analytics - if + the user has access level lower than REPORTER, don't include commit count in + summary + +--- + ...y-ag-cycle-analytics-guest-permissions.yml | 5 +++++ + lib/gitlab/cycle_analytics/stage_summary.rb | 22 ++++++++++++++++--- + spec/features/cycle_analytics_spec.rb | 10 ++++++++- + .../cycle_analytics/stage_summary_spec.rb | 21 ++++++++++++++++++ + 4 files changed, 54 insertions(+), 4 deletions(-) + create mode 100644 changelogs/unreleased/security-ag-cycle-analytics-guest-permissions.yml + +diff --git a/changelogs/unreleased/security-ag-cycle-analytics-guest-permissions.yml b/changelogs/unreleased/security-ag-cycle-analytics-guest-permissions.yml +new file mode 100644 +index 000000000000..c7a3b8923cdf +--- /dev/null ++++ b/changelogs/unreleased/security-ag-cycle-analytics-guest-permissions.yml +@@ -0,0 +1,5 @@ ++--- ++title: Hide commit counts from guest users in Cycle Analytics. ++merge_request: ++author: ++type: security +diff --git a/lib/gitlab/cycle_analytics/stage_summary.rb b/lib/gitlab/cycle_analytics/stage_summary.rb +index 5198dd5b4eb6..c0ee65a106d1 100644 +--- a/lib/gitlab/cycle_analytics/stage_summary.rb ++++ b/lib/gitlab/cycle_analytics/stage_summary.rb +@@ -10,13 +10,29 @@ module Gitlab + end + + def data +- [serialize(Summary::Issue.new(project: @project, from: @from, current_user: @current_user)), +- serialize(Summary::Commit.new(project: @project, from: @from)), +- serialize(Summary::Deploy.new(project: @project, from: @from))] ++ summary = [issue_stats] ++ summary << commit_stats if user_has_sufficient_access? ++ summary << deploy_stats + end + + private + ++ def issue_stats ++ serialize(Summary::Issue.new(project: @project, from: @from, current_user: @current_user)) ++ end ++ ++ def commit_stats ++ serialize(Summary::Commit.new(project: @project, from: @from)) ++ end ++ ++ def deploy_stats ++ serialize(Summary::Deploy.new(project: @project, from: @from)) ++ end ++ ++ def user_has_sufficient_access? ++ @project.team.member?(@current_user, Gitlab::Access::REPORTER) ++ end ++ + def serialize(summary_object) + AnalyticsSummarySerializer.new.represent(summary_object) + end +diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb +index 07f0864fb3ba..df8d5124f36e 100644 +--- a/spec/features/cycle_analytics_spec.rb ++++ b/spec/features/cycle_analytics_spec.rb +@@ -108,6 +108,10 @@ describe 'Cycle Analytics', :js do + wait_for_requests + end + ++ it 'does not show the commit stats' do ++ expect(page).to have_no_selector(:xpath, commits_counter_selector) ++ end ++ + it 'needs permissions to see restricted stages' do + expect(find('.stage-events')).to have_content(issue.title) + +@@ -123,8 +127,12 @@ describe 'Cycle Analytics', :js do + find(:xpath, "//p[contains(text(),'New Issue')]/preceding-sibling::h3") + end + ++ def commits_counter_selector ++ "//p[contains(text(),'Commits')]/preceding-sibling::h3" ++ end ++ + def commits_counter +- find(:xpath, "//p[contains(text(),'Commits')]/preceding-sibling::h3") ++ find(:xpath, commits_counter_selector) + end + + def deploys_counter +diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb +index 778c2f479b56..35bfeae5ea24 100644 +--- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb ++++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb +@@ -8,6 +8,10 @@ describe Gitlab::CycleAnalytics::StageSummary do + let(:user) { create(:user, :admin) } + subject { described_class.new(project, from: Time.now, current_user: user).data } + ++ before do ++ project.add_maintainer(user) ++ end ++ + describe "#new_issues" do + it "finds the number of issues created after the 'from date'" do + Timecop.freeze(5.days.ago) { create(:issue, project: project) } +@@ -42,6 +46,23 @@ describe Gitlab::CycleAnalytics::StageSummary do + + expect(subject.second[:value]).to eq(100) + end ++ ++ context 'when a guest user is signed in' do ++ let(:guest_user) { create(:user) } ++ ++ before do ++ project.add_guest(guest_user) ++ end ++ ++ it 'does not include commit stats' do ++ data = described_class.new(project, from: from, current_user: guest_user).data ++ expect(includes_commits?(data)).to be_falsy ++ end ++ ++ def includes_commits?(data) ++ data.any? { |h| h["title"] == 'Commits' } ++ end ++ end + end + + describe "#deploys" do +-- +2.22.0 + diff --git a/debian/patches/CVE-2019-19257.patch b/debian/patches/CVE-2019-19257.patch new file mode 100644 index 0000000000..28447b330e --- /dev/null +++ b/debian/patches/CVE-2019-19257.patch @@ -0,0 +1,181 @@ +From debb36496b4805beae28262fbb24a692018178e2 Mon Sep 17 00:00:00 2001 +From: Kerri Miller +Date: Fri, 25 Oct 2019 07:46:40 -0500 +Subject: [PATCH] Restrict branches visible to guests in Issue feed + +Notes related to branch creation should not be shown in an issue's +activity feed when the user doesn't have access to :download_code. +--- + app/models/note.rb | 15 ++++- + ...er-related-branches-from-activity-feed.yml | 6 ++ + .../projects/issues_controller_spec.rb | 37 +++++++++++ + spec/models/note_spec.rb | 64 +++++++++++++++++++ + 4 files changed, 121 insertions(+), 1 deletion(-) + create mode 100644 changelogs/unreleased/security-filter-related-branches-from-activity-feed.yml + +--- a/app/models/note.rb ++++ b/app/models/note.rb +@@ -40,6 +40,10 @@ + + redact_field :note + ++ TYPES_RESTRICTED_BY_ABILITY = { ++ branch: :download_code ++ }.freeze ++ + # Aliases to make application_helper#edited_time_ago_with_tooltip helper work properly with notes. + # See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10392/diffs#note_28719102 + alias_attribute :last_edited_at, :updated_at +@@ -333,7 +337,7 @@ + end + + def visible_for?(user) +- !cross_reference_not_visible_for?(user) ++ !cross_reference_not_visible_for?(user) && system_note_viewable_by?(user) + end + + def award_emoji? +@@ -485,6 +489,15 @@ + + private + ++ def system_note_viewable_by?(user) ++ return true unless system_note_metadata ++ ++ restriction = TYPES_RESTRICTED_BY_ABILITY[system_note_metadata.action.to_sym] ++ return Ability.allowed?(user, restriction, project) if restriction ++ ++ true ++ end ++ + def keep_around_commit + project.repository.keep_around(self.commit_id) + end +--- /dev/null ++++ b/changelogs/unreleased/security-filter-related-branches-from-activity-feed.yml +@@ -0,0 +1,6 @@ ++--- ++title: Remove notes regarding Related Branches from Issue activity feeds for guest ++ users ++merge_request: ++author: ++type: security +--- a/spec/controllers/projects/issues_controller_spec.rb ++++ b/spec/controllers/projects/issues_controller_spec.rb +@@ -1343,6 +1343,43 @@ + expect { get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } }.not_to exceed_query_limit(control_count) + end + end ++ ++ context 'private project' do ++ let!(:branch_note) { create(:discussion_note_on_issue, :system, noteable: issue, project: project) } ++ let!(:commit_note) { create(:discussion_note_on_issue, :system, noteable: issue, project: project) } ++ let!(:branch_note_meta) { create(:system_note_metadata, note: branch_note, action: "branch") } ++ let!(:commit_note_meta) { create(:system_note_metadata, note: commit_note, action: "commit") } ++ ++ context 'user is allowed access' do ++ before do ++ project.add_user(user, :maintainer) ++ end ++ ++ it 'displays all available notes' do ++ get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } ++ ++ expect(json_response.length).to eq(3) ++ end ++ end ++ ++ context 'user is a guest' do ++ let(:json_response_note_ids) do ++ json_response.collect { |discussion| discussion["notes"] }.flatten ++ .collect { |note| note["id"].to_i } ++ end ++ ++ before do ++ project.add_guest(user) ++ end ++ ++ it 'does not display notes w/type listed in TYPES_RESTRICTED_BY_ACCESS_LEVEL' do ++ get :discussions, params: { namespace_id: project.namespace, project_id: project, id: issue.iid } ++ ++ expect(json_response.length).to eq(2) ++ expect(json_response_note_ids).not_to include(branch_note.id) ++ end ++ end ++ end + end + end + +--- a/spec/models/note_spec.rb ++++ b/spec/models/note_spec.rb +@@ -246,6 +246,70 @@ + end + end + ++ describe "#visible_for?" do ++ using RSpec::Parameterized::TableSyntax ++ ++ let(:note) { create(:note) } ++ let(:user) { create(:user) } ++ ++ where(:cross_reference_visible, :system_note_viewable, :result) do ++ true | true | false ++ false | true | true ++ false | false | false ++ end ++ ++ with_them do ++ it "returns expected result" do ++ expect(note).to receive(:cross_reference_not_visible_for?).and_return(cross_reference_visible) ++ ++ unless cross_reference_visible ++ expect(note).to receive(:system_note_viewable_by?) ++ .with(user).and_return(system_note_viewable) ++ end ++ ++ expect(note.visible_for?(user)).to eq result ++ end ++ end ++ end ++ ++ describe "#system_note_viewable_by?(user)" do ++ let(:note) { create(:note) } ++ let(:user) { create(:user) } ++ let!(:metadata) { create(:system_note_metadata, note: note, action: "branch") } ++ ++ context "when system_note_metadata is not present" do ++ it "returns true" do ++ expect(note).to receive(:system_note_metadata).and_return(nil) ++ ++ expect(note.send(:system_note_viewable_by?, user)).to be_truthy ++ end ++ end ++ ++ context "system_note_metadata isn't of type 'branch'" do ++ before do ++ metadata.action = "not_a_branch" ++ end ++ ++ it "returns true" do ++ expect(note.send(:system_note_viewable_by?, user)).to be_truthy ++ end ++ end ++ ++ context "user doesn't have :download_code ability" do ++ it "returns false" do ++ expect(note.send(:system_note_viewable_by?, user)).to be_falsey ++ end ++ end ++ ++ context "user has the :download_code ability" do ++ it "returns true" do ++ expect(Ability).to receive(:allowed?).with(user, :download_code, note.project).and_return(true) ++ ++ expect(note.send(:system_note_viewable_by?, user)).to be_truthy ++ end ++ end ++ end ++ + describe "cross_reference_not_visible_for?" do + let(:private_user) { create(:user) } + let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_maintainer(private_user) } } diff --git a/debian/patches/series b/debian/patches/series index 11e476f794..024edb21c5 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -27,3 +27,5 @@ 0750-fix-relative-paths.patch 0760-bump-rubyzip.patch 0770-bump-node-d3.patch +CVE-2019-19254.patch +CVE-2019-19257.patch