Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 225 additions & 20 deletions spec/request/route_destinations_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,14 @@
expect(last_response.status).to eq(422)
expect(last_response).to have_error_message("Routes destinations must be in either the route's space or the route's shared spaces")
end

it 'returns 422 even when the user has space_developer in both the route space and the app space' do
# Having write access to both spaces is not enough — the route must be explicitly shared
set_current_user_as_role(user: user, role: 'space_developer', org: space.organization, space: space)
post "/v3/routes/#{route.guid}/destinations", params.to_json, user_header
expect(last_response.status).to eq(422)
expect(last_response).to have_error_message("Routes destinations must be in either the route's space or the route's shared spaces")
end
end

context 'when the app does not exist' do
Expand Down Expand Up @@ -583,6 +591,69 @@
end
end
end

context "when the app is in the route's shared space" do
let(:shared_app_space) { create(:space) }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let(:api_call) do
lambda do |user_headers|
params = { destinations: [{ app: { guid: shared_app.guid, process: { type: 'web' } } }] }
post "/v3/routes/#{route.guid}/destinations", params.to_json, user_headers
end
end
let(:expected_codes_and_responses) do
h = Hash.new({ code: 403, errors: CF_NOT_AUTHORIZED }.freeze)
h['admin'] = { code: 200 }
h['space_developer'] = { code: 200 }
h['space_supporter'] = { code: 200 }
h['org_billing_manager'] = { code: 404 }
h['no_role'] = { code: 404 }
h
end

before do
route.add_shared_space shared_app_space
shared_app_space.organization.add_user(user)
shared_app_space.add_developer(user)
end

it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
end

context "when the app is in the route's shared space - roles in the shared space" do
let(:route_space) { create(:space) }
let(:route) { create(:route, space: route_space) }
let(:shared_app_space) { create(:space) }
let(:org) { shared_app_space.organization }
let(:space) { shared_app_space }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let(:api_call) do
lambda do |user_headers|
params = { destinations: [{ app: { guid: shared_app.guid, process: { type: 'web' } } }] }
post "/v3/routes/#{route.guid}/destinations", params.to_json, user_headers
end
end
let(:expected_codes_and_responses) do
h = Hash.new({ code: 422 }.freeze)
h['admin'] = { code: 200 }
h['space_developer'] = { code: 200 }
h['space_manager'] = { code: 200 }
h['space_auditor'] = { code: 200 }
h['space_supporter'] = { code: 200 }
h['org_manager'] = { code: 200 }
h['admin_read_only'] = { code: 200 }
h['global_auditor'] = { code: 200 }
h
end

before do
route.add_shared_space shared_app_space
route_space.organization.add_user(user)
route_space.add_developer(user)
end

it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
end
end

describe 'PATCH /v3/routes/:guid/destinations' do
Expand Down Expand Up @@ -1175,32 +1246,66 @@
end

context "when the app is in the route's shared space" do
let(:app_model) { create(:app_model) }
let(:params) do
{
destinations: [
{
app: {
guid: app_model.guid,
process: {
type: 'web'
}
}
}
]
}
let(:shared_app_space) { create(:space) }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let(:api_call) do
lambda do |user_headers|
params = { destinations: [{ app: { guid: shared_app.guid, process: { type: 'web' } } }] }
patch "/v3/routes/#{route.guid}/destinations", params.to_json, user_headers
end
end
let(:expected_codes_and_responses) do
h = Hash.new({ code: 403, errors: CF_NOT_AUTHORIZED }.freeze)
h['admin'] = { code: 200 }
h['space_developer'] = { code: 200 }
h['space_supporter'] = { code: 200 }
h['org_billing_manager'] = { code: 404 }
h['no_role'] = { code: 404 }
h
end

before do
route.add_shared_space app_model.space
set_current_user_as_role(user: user, role: 'space_developer', org: space.organization, space: space)
set_current_user_as_role(user: user, role: 'space_developer', org: app_model.space.organization, space: app_model.space)
route.add_shared_space shared_app_space
shared_app_space.organization.add_user(user)
shared_app_space.add_developer(user)
end

it 'succeeds' do
patch "/v3/routes/#{route.guid}/destinations", params.to_json, user_header
expect(last_response.status).to eq(200)
it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
end

context "when the app is in the route's shared space - roles in the shared space" do
let(:route_space) { create(:space) }
let(:route) { create(:route, space: route_space) }
let(:shared_app_space) { create(:space) }
let(:org) { shared_app_space.organization }
let(:space) { shared_app_space }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let(:api_call) do
lambda do |user_headers|
params = { destinations: [{ app: { guid: shared_app.guid, process: { type: 'web' } } }] }
patch "/v3/routes/#{route.guid}/destinations", params.to_json, user_headers
end
end
let(:expected_codes_and_responses) do
h = Hash.new({ code: 422 }.freeze)
h['admin'] = { code: 200 }
h['space_developer'] = { code: 200 }
h['space_manager'] = { code: 200 }
h['space_auditor'] = { code: 200 }
h['space_supporter'] = { code: 200 }
h['org_manager'] = { code: 200 }
h['admin_read_only'] = { code: 200 }
h['global_auditor'] = { code: 200 }
h
end

before do
route.add_shared_space shared_app_space
route_space.organization.add_user(user)
route_space.add_developer(user)
end

it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
end
end

Expand Down Expand Up @@ -1298,6 +1403,55 @@
end
end

context "when the destination app is in the route's shared space" do
let(:shared_app_space) { create(:space) }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let!(:shared_destination) do
create(:route_mapping_model, app: shared_app, route: route, process_type: 'web',
app_port: VCAP::CloudController::ProcessModel::DEFAULT_HTTP_PORT, weight: nil)
end
let(:api_call) { ->(user_headers) { patch "/v3/routes/#{route.guid}/destinations/#{shared_destination.guid}", { protocol: 'http1' }.to_json, user_headers } }
let(:expected_codes_and_responses) do
h = Hash.new({ code: 403, errors: CF_NOT_AUTHORIZED }.freeze)
h['admin'] = { code: 200 }
h['space_developer'] = { code: 200 }
h['space_supporter'] = { code: 200 }
h['org_billing_manager'] = { code: 404 }
h['no_role'] = { code: 404 }
h
end

before { route.add_shared_space shared_app_space }

it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
end

context "when the destination app is in the route's shared space - roles in the shared space" do
let(:route_space) { create(:space) }
let(:route) { create(:route, space: route_space) }
let(:shared_app_space) { create(:space) }
let(:org) { shared_app_space.organization }
let(:space) { shared_app_space }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let!(:shared_destination) do
create(:route_mapping_model, app: shared_app, route: route, process_type: 'web',
app_port: VCAP::CloudController::ProcessModel::DEFAULT_HTTP_PORT, weight: nil)
end
let(:api_call) { ->(user_headers) { patch "/v3/routes/#{route.guid}/destinations/#{shared_destination.guid}", { protocol: 'http1' }.to_json, user_headers } }
let(:expected_codes_and_responses) do
h = Hash.new({ code: 200 }.freeze)
h
end

before do
route.add_shared_space shared_app_space
route_space.organization.add_user(user)
route_space.add_developer(user)
end

it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
end

context 'when the route has a protocol of tcp' do
let(:routing_api_client) { double('routing_api_client', router_group:) }
let(:router_group) { double('router_group', type: 'tcp', guid: 'router-group-guid') }
Expand Down Expand Up @@ -1458,6 +1612,57 @@
end
end

context "when the destination app is in the route's shared space" do
let(:shared_app_space) { create(:space) }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let!(:shared_destination) do
create(:route_mapping_model, app: shared_app, route: route, process_type: 'web',
app_port: VCAP::CloudController::ProcessModel::DEFAULT_HTTP_PORT, weight: nil)
end
let(:api_call) { ->(user_headers) { delete "/v3/routes/#{route.guid}/destinations/#{shared_destination.guid}", nil, user_headers } }
let(:db_check) { -> {} }
let(:expected_codes_and_responses) do
h = Hash.new({ code: 403, errors: CF_NOT_AUTHORIZED }.freeze)
h['admin'] = { code: 204 }
h['space_developer'] = { code: 204 }
h['space_supporter'] = { code: 204 }
h['org_billing_manager'] = { code: 404 }
h['no_role'] = { code: 404 }
h
end

before { route.add_shared_space shared_app_space }

it_behaves_like 'permissions for delete endpoint', ALL_PERMISSIONS
end

context "when the destination app is in the route's shared space - roles in the shared space" do
let(:route_space) { create(:space) }
let(:route) { create(:route, space: route_space) }
let(:shared_app_space) { create(:space) }
let(:org) { shared_app_space.organization }
let(:space) { shared_app_space }
let(:shared_app) { create(:app_model, space: shared_app_space) }
let!(:shared_destination) do
create(:route_mapping_model, app: shared_app, route: route, process_type: 'web',
app_port: VCAP::CloudController::ProcessModel::DEFAULT_HTTP_PORT, weight: nil)
end
let(:api_call) { ->(user_headers) { delete "/v3/routes/#{route.guid}/destinations/#{shared_destination.guid}", nil, user_headers } }
let(:db_check) { -> {} }
let(:expected_codes_and_responses) do
h = Hash.new({ code: 204 }.freeze)
h
end

before do
route.add_shared_space shared_app_space
route_space.organization.add_user(user)
route_space.add_developer(user)
end

it_behaves_like 'permissions for delete endpoint', ALL_PERMISSIONS
end

context 'when there is an existing weighted destination' do
let!(:existing_destination) { create(:route_mapping_model, app: app_model, process_type: 'something', route: route, weight: 10) }

Expand Down
Loading