Skip to content

Commit e9cc2df

Browse files
committed
Make split deletion only accessible to owning app
1 parent 18dd404 commit e9cc2df

3 files changed

Lines changed: 51 additions & 31 deletions

File tree

app/controllers/api/v1/split_configs_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def create
99
end
1010

1111
def destroy
12-
split = Split.find_by!(name: params[:id])
12+
split = current_app.splits.find_by!(name: params[:id])
1313
split.update!(finished_at: Time.zone.now) unless split.finished?
1414
head :no_content
1515
end

app/controllers/authenticated_api_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class AuthenticatedApiController < UnauthenticatedApiController
55
attr_reader :current_app
66

77
def authenticate
8-
authenticate_with_http_basic do |app_name, auth_secret|
8+
authenticate_or_request_with_http_basic do |app_name, auth_secret|
99
app = App.find_by(name: app_name)
1010
if app && ActiveSupport::SecurityUtils.secure_compare(app.auth_secret, auth_secret)
1111
@current_app = app

spec/controllers/api/v1/split_configs_controller_spec.rb

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,73 @@
33
RSpec.describe Api::V1::SplitConfigsController, type: :controller do
44
let(:default_app) { FactoryGirl.create :app, name: "default_app", auth_secret: "6Sd6T7T6Q8hKcoo0t8CTzV0IdN1EEHqXB2Ig4raZsOU" }
55

6-
before do
7-
http_authenticate username: default_app.name, auth_secret: default_app.auth_secret
8-
end
9-
106
describe '#create' do
11-
it "creates a new split with desired weightings" do
7+
it "doesn't create when unauthenticated" do
128
post :create, name: 'foobar', weighting_registry: { foo: 10, bar: 90 }
139

14-
expect(response).to have_http_status(:no_content)
15-
split = Split.find_by(name: 'foobar', owner_app: default_app)
16-
expect(split).to be_truthy
17-
expect(split.registry).to eq 'foo' => 10, 'bar' => 90
10+
expect(response).to have_http_status(:unauthorized)
11+
expect(Split.where(name: 'foobar')).to be_empty
1812
end
13+
end
1914

20-
it 'returns errors when invalid' do
21-
post :create, name: 'fooBar', weighting_registry: { foo: 10, bar: 90 }
22-
expect(response).to have_http_status(:unprocessable_entity)
23-
expect(response_json['errors']['name'].first).to include("snake_case")
15+
describe "while authenticated" do
16+
before do
17+
http_authenticate username: default_app.name, auth_secret: default_app.auth_secret
2418
end
25-
end
2619

27-
describe '#destroy' do
28-
it "sets the finished_at time on the split" do
29-
split = FactoryGirl.create(:split, name: "old_split", owner_app: default_app, finished_at: nil)
20+
describe '#create' do
21+
it "creates a new split with desired weightings" do
22+
post :create, name: 'foobar', weighting_registry: { foo: 10, bar: 90 }
3023

31-
delete :destroy, id: "old_split"
24+
expect(response).to have_http_status(:no_content)
25+
split = Split.find_by(name: 'foobar', owner_app: default_app)
26+
expect(split).to be_truthy
27+
expect(split.registry).to eq 'foo' => 10, 'bar' => 90
28+
end
3229

33-
expect(response).to have_http_status(:no_content)
34-
expect(split.reload).to be_finished
30+
it 'returns errors when invalid' do
31+
post :create, name: 'fooBar', weighting_registry: { foo: 10, bar: 90 }
32+
expect(response).to have_http_status(:unprocessable_entity)
33+
expect(response_json['errors']['name'].first).to include("snake_case")
34+
end
3535
end
3636

37-
it "is idempotent" do
38-
split = FactoryGirl.create(:split, name: "old_split", owner_app: default_app, finished_at: nil)
37+
describe '#destroy' do
38+
it "sets the finished_at time on the split" do
39+
split = FactoryGirl.create(:split, name: "old_split", owner_app: default_app, finished_at: nil)
3940

40-
Timecop.freeze(Time.zone.parse('2011-01-01')) do
4141
delete :destroy, id: "old_split"
42+
43+
expect(response).to have_http_status(:no_content)
44+
expect(split.reload).to be_finished
4245
end
4346

44-
expect(response).to have_http_status(:no_content)
45-
expect(split.reload.finished_at).to eq Time.zone.parse('2011-01-01')
47+
it "can't delete another app's split" do
48+
other_app = FactoryGirl.create :app, name: "other_app"
49+
split = FactoryGirl.create(:split, name: "other_split", owner_app: other_app, finished_at: nil)
4650

47-
Timecop.freeze(Time.zone.parse('2011-01-02')) do
48-
delete :destroy, id: "old_split"
51+
expect { delete :destroy, id: "other_split" }.to raise_error(ActiveRecord::RecordNotFound)
52+
53+
expect(split.reload).not_to be_finished
4954
end
5055

51-
expect(response).to have_http_status(:no_content)
52-
expect(split.reload.finished_at).to eq Time.zone.parse('2011-01-01')
56+
it "is idempotent" do
57+
split = FactoryGirl.create(:split, name: "old_split", owner_app: default_app, finished_at: nil)
58+
59+
Timecop.freeze(Time.zone.parse('2011-01-01')) do
60+
delete :destroy, id: "old_split"
61+
end
62+
63+
expect(response).to have_http_status(:no_content)
64+
expect(split.reload.finished_at).to eq Time.zone.parse('2011-01-01')
65+
66+
Timecop.freeze(Time.zone.parse('2011-01-02')) do
67+
delete :destroy, id: "old_split"
68+
end
69+
70+
expect(response).to have_http_status(:no_content)
71+
expect(split.reload.finished_at).to eq Time.zone.parse('2011-01-01')
72+
end
5373
end
5474
end
5575
end

0 commit comments

Comments
 (0)