Restrict access to confidential issues through API

parent eb9165e6
......@@ -22,6 +22,20 @@ module API
issues.includes(:milestone).where('milestones.title' => milestone)
end
def filter_issues_confidentiality(issues)
if current_user.admin? || user_project.team.member?(current_user.id)
issues
else
issuable_table = issues.arel_table
issues.where(
issuable_table[:confidential].eq(false).or(
issuable_table[:author_id].eq(current_user.id).and(issuable_table[:confidential].eq(true))
)
)
end
end
def create_spam_log(project, current_user, attrs)
params = attrs.merge({
source_ip: env['REMOTE_ADDR'],
......@@ -86,6 +100,7 @@ module API
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
issues = filter_issues_confidentiality(issues)
unless params[:milestone].nil?
issues = filter_issues_milestone(issues, params[:milestone])
......@@ -104,6 +119,7 @@ module API
# GET /projects/:id/issues/:issue_id
get ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id])
not_found! unless can?(current_user, :read_issue, @issue)
present @issue, with: Entities::Issue
end
......
......@@ -3,7 +3,10 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
let(:non_member) { create(:user) }
let(:author) { create(:author) }
let(:admin) { create(:admin) }
let!(:project) { create(:project, :public, namespace: user.namespace ) }
let!(:closed_issue) do
create :closed_issue,
author: user,
......@@ -12,6 +15,12 @@ describe API::API, api: true do
state: :closed,
milestone: milestone
end
let!(:confidential_issue) do
create :issue,
:confidential,
project: project,
author: author
end
let!(:issue) do
create :issue,
author: user,
......@@ -123,10 +132,35 @@ describe API::API, api: true do
let(:base_url) { "/projects/#{project.id}" }
let(:title) { milestone.title }
it "should return project issues" do
it 'should return project issues without confidential issues for non project members' do
get api("#{base_url}/issues", non_member)
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)
expect(json_response).to be_an Array
expect(json_response.length).to eq(3)
expect(json_response.first['title']).to eq(issue.title)
end
it 'should return project issues with confidential issues for project members' do
get api("#{base_url}/issues", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(3)
expect(json_response.first['title']).to eq(issue.title)
end
it 'should return project confidential issues for admin' do
get api("#{base_url}/issues", admin)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(3)
expect(json_response.first['title']).to eq(issue.title)
end
......@@ -206,6 +240,34 @@ describe API::API, api: true do
get api("/projects/#{project.id}/issues/54321", user)
expect(response.status).to eq(404)
end
context 'confidential issues' do
it "should return 404 for non project members" do
get api("/projects/#{project.id}/issues/#{confidential_issue.id}", non_member)
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)
expect(json_response['title']).to eq(confidential_issue.title)
expect(json_response['iid']).to eq(confidential_issue.iid)
end
it "should return confidential issue for author" do
get api("/projects/#{project.id}/issues/#{confidential_issue.id}", author)
expect(response.status).to eq(200)
expect(json_response['title']).to eq(confidential_issue.title)
expect(json_response['iid']).to eq(confidential_issue.iid)
end
it "should return confidential issue for admin" do
get api("/projects/#{project.id}/issues/#{confidential_issue.id}", admin)
expect(response.status).to eq(200)
expect(json_response['title']).to eq(confidential_issue.title)
expect(json_response['iid']).to eq(confidential_issue.iid)
end
end
end
describe "POST /projects/:id/issues" do
......@@ -294,6 +356,35 @@ describe API::API, api: true do
expect(response.status).to eq(400)
expect(json_response['message']['labels']['?']['title']).to eq(['is invalid'])
end
context 'confidential issues' do
it "should return 403 for non project members" do
put api("/projects/#{project.id}/issues/#{confidential_issue.id}", non_member),
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'
expect(response.status).to eq(200)
expect(json_response['title']).to eq('updated title')
end
it "should update a confidential issue for author" do
put api("/projects/#{project.id}/issues/#{confidential_issue.id}", author),
title: 'updated title'
expect(response.status).to eq(200)
expect(json_response['title']).to eq('updated title')
end
it "should update a confidential issue for admin" do
put api("/projects/#{project.id}/issues/#{confidential_issue.id}", admin),
title: 'updated title'
expect(response.status).to eq(200)
expect(json_response['title']).to eq('updated title')
end
end
end
describe 'PUT /projects/:id/issues/:issue_id to update labels' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment