Skip to content
This repository was archived by the owner on Jun 2, 2021. It is now read-only.

Commit 7395ee8

Browse files
sweinstein22reidmitMerricdeLauney
committed
v3: Surface helpful error when trying to create security group with
invalid name For example, if you `POST /v3/security_groups` with `{"name": "🐧"}`, you used to get a 500. Now, you get a 422 with message "Security group contains invalid characters". Note that in the case of emojis, at least, this error will only occur in MySQL (not Postgres). [Finishes #172574458, #172574465] Co-authored-by: Sarah Weinstein <sweinstein@pivotal.io> Co-authored-by: Reid Mitchell <rmitchell@pivotal.io> Co-authored-by: Merric de Launey <mdelauney@pivotal.io>
1 parent f961fab commit 7395ee8

3 files changed

Lines changed: 139 additions & 18 deletions

File tree

app/actions/security_group_create.rb

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module VCAP::CloudController
22
class SecurityGroupCreate
3+
MYSQL_INVALID_VALUE_ERROR = 1366
4+
35
class Error < ::StandardError
46
end
57

@@ -24,6 +26,8 @@ def create(message)
2426
security_group
2527
rescue Sequel::ValidationFailed => e
2628
validation_error!(e, message)
29+
rescue Sequel::DatabaseError => e
30+
invalid_value_error!(e)
2731
end
2832

2933
private
@@ -36,17 +40,29 @@ def validation_error!(error, message)
3640
error!(error.message)
3741
end
3842

43+
def invalid_value_error!(error)
44+
if error.wrapped_exception.is_a?(Mysql2::Error) && error.wrapped_exception.error_number == MYSQL_INVALID_VALUE_ERROR
45+
if /column 'name'/ =~ error.message
46+
error!('Security group name contains invalid characters.')
47+
elsif /column 'rules'/ =~ error.message
48+
error!('Security group rules contain invalid characters.')
49+
end
50+
end
51+
52+
raise error
53+
end
54+
55+
def error!(message)
56+
raise Error.new(message)
57+
end
58+
3959
def valid_spaces(space_guids)
4060
spaces = Space.where(guid: space_guids).all
4161
return spaces if spaces.length == space_guids.length
4262

4363
invalid_space_guids = space_guids - spaces.map(&:guid)
4464
error!("Spaces with guids #{invalid_space_guids} do not exist.")
4565
end
46-
47-
def error!(message)
48-
raise Error.new(message)
49-
end
5066
end
5167
end
5268
end
Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,56 @@
11
module VCAP::CloudController
22
class SecurityGroupUpdate
3+
MYSQL_INVALID_VALUE_ERROR = 1366
4+
35
class Error < ::StandardError
46
end
57

6-
def self.update(security_group, message)
7-
security_group.db.transaction do
8-
security_group.lock!
8+
class << self
9+
def update(security_group, message)
10+
security_group.db.transaction do
11+
security_group.lock!
12+
13+
security_group.name = message.name if message.requested? :name
14+
security_group.rules = message.rules if message.requested? :rules
15+
16+
security_group.staging_default = message.staging if message.requested?(:globally_enabled) && !message.staging.nil?
17+
security_group.running_default = message.running if message.requested?(:globally_enabled) && !message.running.nil?
18+
19+
security_group.save
20+
end
921

10-
security_group.name = message.name if message.requested? :name
11-
security_group.rules = message.rules if message.requested? :rules
22+
security_group
23+
rescue Sequel::ValidationFailed => e
24+
validation_error!(e, message)
25+
rescue Sequel::DatabaseError => e
26+
invalid_value_error!(e)
27+
end
28+
29+
private
1230

13-
security_group.staging_default = message.staging if message.requested?(:globally_enabled) && !message.staging.nil?
14-
security_group.running_default = message.running if message.requested?(:globally_enabled) && !message.running.nil?
31+
def validation_error!(error, message)
32+
if error.errors.on(:name)&.include?(:unique)
33+
error!("Security group with name '#{message.name}' already exists.")
34+
end
1535

16-
security_group.save
36+
error!(error.message)
1737
end
1838

19-
security_group
20-
rescue Sequel::ValidationFailed => e
21-
if e.errors.on(:name)&.include?(:unique)
22-
raise Error.new("Security group with name '#{message.name}' already exists.")
39+
def invalid_value_error!(error)
40+
if error.wrapped_exception.is_a?(Mysql2::Error) && error.wrapped_exception.error_number == MYSQL_INVALID_VALUE_ERROR
41+
if /column 'name'/ =~ error.message
42+
error!('Security group name contains invalid characters.')
43+
elsif /column 'rules'/ =~ error.message
44+
error!('Security group rules contain invalid characters.')
45+
end
46+
end
47+
48+
raise error
2349
end
2450

25-
raise Error.new(e.message)
51+
def error!(message)
52+
raise Error.new(message)
53+
end
2654
end
2755
end
2856
end

spec/request/security_groups_spec.rb

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,46 @@
143143
it_behaves_like 'permissions for single object endpoint', ALL_PERMISSIONS
144144
end
145145

146-
context 'when a security group with that name already exists' do
146+
if ENV['DB'] == 'mysql'
147+
context 'when the security group name is invalid' do
148+
let(:params) do
149+
{
150+
name: '🐸🐞'
151+
}
152+
end
153+
154+
it 'returns a 422 with a helpful message' do
155+
post '/v3/security_groups', params.to_json, admin_header
156+
157+
expect(last_response).to have_status_code(422)
158+
expect(last_response).to have_error_message(
159+
'Security group name contains invalid characters.'
160+
)
161+
end
162+
end
163+
164+
context 'when the security group rules are invalid' do
165+
let(:params) do
166+
{
167+
name: 'bad-rules',
168+
rules: [
169+
{ "protocol": 'all', "destination": '0.0.0.0', "description": 'asd🐞f' }
170+
]
171+
}
172+
end
173+
174+
it 'returns a 422 with a helpful message' do
175+
post '/v3/security_groups', params.to_json, admin_header
176+
177+
expect(last_response).to have_status_code(422)
178+
expect(last_response).to have_error_message(
179+
'Security group rules contain invalid characters.'
180+
)
181+
end
182+
end
183+
end
184+
185+
context 'when a security group with name that already exists' do
147186
before do
148187
post '/v3/security_groups', params.to_json, admin_header
149188
end
@@ -1107,6 +1146,44 @@
11071146
expect(last_response).to have_error_message("Security group with name 'already-taken' already exists")
11081147
end
11091148
end
1149+
1150+
if ENV['DB'] == 'mysql'
1151+
context 'when the security group name is invalid' do
1152+
let(:params) do
1153+
{
1154+
name: '🐸🐞'
1155+
}
1156+
end
1157+
1158+
it 'returns a 422 with a helpful message' do
1159+
patch "/v3/security_groups/#{security_group.guid}", params.to_json, admin_header
1160+
1161+
expect(last_response).to have_status_code(422)
1162+
expect(last_response).to have_error_message(
1163+
'Security group name contains invalid characters.'
1164+
)
1165+
end
1166+
end
1167+
1168+
context 'when the security group rules are invalid' do
1169+
let(:params) do
1170+
{
1171+
rules: [
1172+
{ "protocol": 'all', "destination": '0.0.0.0', "description": 'asd🐞f' }
1173+
]
1174+
}
1175+
end
1176+
1177+
it 'returns a 422 with a helpful message' do
1178+
patch "/v3/security_groups/#{security_group.guid}", params.to_json, admin_header
1179+
1180+
expect(last_response).to have_status_code(422)
1181+
expect(last_response).to have_error_message(
1182+
'Security group rules contain invalid characters.'
1183+
)
1184+
end
1185+
end
1186+
end
11101187
end
11111188

11121189
describe 'DELETE /v3/security_groups/:security_group_guid/relationships/running_spaces/:space_guid' do

0 commit comments

Comments
 (0)