Commit 22b9dd0f authored by Hordur Freyr Yngvason's avatar Hordur Freyr Yngvason

Do not expose Terraform state record in API

In particular, do not expose the object storage URL, which could be used
to write unwanted artifacts, bypassing backend validation.

See https://gitlab.com/gitlab-org/gitlab/-/issues/250266
parent 524ae855
...@@ -23,6 +23,8 @@ module Terraform ...@@ -23,6 +23,8 @@ module Terraform
state.save! unless state.destroyed? state.save! unless state.destroyed?
end end
nil
end end
def lock! def lock!
......
---
title: Do not expose Terraform state record in API
merge_request:
author:
type: security
...@@ -39,7 +39,6 @@ module API ...@@ -39,7 +39,6 @@ module API
env['api.format'] = :binary # this bypasses json serialization env['api.format'] = :binary # this bypasses json serialization
body state.latest_file.read body state.latest_file.read
status :ok
end end
end end
...@@ -53,8 +52,10 @@ module API ...@@ -53,8 +52,10 @@ module API
remote_state_handler.handle_with_lock do |state| remote_state_handler.handle_with_lock do |state|
state.update_file!(CarrierWaveStringFile.new(data), version: params[:serial], build: current_authenticated_job) state.update_file!(CarrierWaveStringFile.new(data), version: params[:serial], build: current_authenticated_job)
status :ok
end end
body false
status :ok
end end
desc 'Delete a terraform state of a certain name' desc 'Delete a terraform state of a certain name'
...@@ -64,8 +65,10 @@ module API ...@@ -64,8 +65,10 @@ module API
remote_state_handler.handle_with_lock do |state| remote_state_handler.handle_with_lock do |state|
state.destroy! state.destroy!
status :ok
end end
body false
status :ok
end end
desc 'Lock a terraform state of a certain name' desc 'Lock a terraform state of a certain name'
......
...@@ -125,6 +125,7 @@ RSpec.describe API::Terraform::State do ...@@ -125,6 +125,7 @@ RSpec.describe API::Terraform::State do
expect { request }.to change { Terraform::State.count }.by(0) expect { request }.to change { Terraform::State.count }.by(0)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Json.parse(response.body)).to be_empty
end end
context 'on Unicorn', :unicorn do context 'on Unicorn', :unicorn do
...@@ -132,6 +133,7 @@ RSpec.describe API::Terraform::State do ...@@ -132,6 +133,7 @@ RSpec.describe API::Terraform::State do
expect { request }.to change { Terraform::State.count }.by(0) expect { request }.to change { Terraform::State.count }.by(0)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Json.parse(response.body)).to be_empty
end end
end end
end end
...@@ -167,6 +169,7 @@ RSpec.describe API::Terraform::State do ...@@ -167,6 +169,7 @@ RSpec.describe API::Terraform::State do
expect { request }.to change { Terraform::State.count }.by(1) expect { request }.to change { Terraform::State.count }.by(1)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Json.parse(response.body)).to be_empty
end end
context 'on Unicorn', :unicorn do context 'on Unicorn', :unicorn do
...@@ -174,6 +177,7 @@ RSpec.describe API::Terraform::State do ...@@ -174,6 +177,7 @@ RSpec.describe API::Terraform::State do
expect { request }.to change { Terraform::State.count }.by(1) expect { request }.to change { Terraform::State.count }.by(1)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Json.parse(response.body)).to be_empty
end end
end end
end end
...@@ -218,10 +222,11 @@ RSpec.describe API::Terraform::State do ...@@ -218,10 +222,11 @@ RSpec.describe API::Terraform::State do
context 'with maintainer permissions' do context 'with maintainer permissions' do
let(:current_user) { maintainer } let(:current_user) { maintainer }
it 'deletes the state' do it 'deletes the state and returns empty body' do
expect { request }.to change { Terraform::State.count }.by(-1) expect { request }.to change { Terraform::State.count }.by(-1)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(Gitlab::Json.parse(response.body)).to be_empty
end end
end end
......
...@@ -42,17 +42,17 @@ RSpec.describe Terraform::RemoteStateHandler do ...@@ -42,17 +42,17 @@ RSpec.describe Terraform::RemoteStateHandler do
describe '#handle_with_lock' do describe '#handle_with_lock' do
it 'allows to modify a state using database locking' do it 'allows to modify a state using database locking' do
state = subject.handle_with_lock do |state| record = nil
subject.handle_with_lock do |state|
record = state
state.name = 'updated-name' state.name = 'updated-name'
end end
expect(state.name).to eq 'updated-name' expect(record.reload.name).to eq 'updated-name'
end end
it 'returns the state object itself' do it 'returns nil' do
state = subject.handle_with_lock expect(subject.handle_with_lock).to be_nil
expect(state.name).to eq 'my-state'
end end
end end
...@@ -70,11 +70,13 @@ RSpec.describe Terraform::RemoteStateHandler do ...@@ -70,11 +70,13 @@ RSpec.describe Terraform::RemoteStateHandler do
it 'handles a locked state using exclusive read lock' do it 'handles a locked state using exclusive read lock' do
handler.lock! handler.lock!
state = handler.handle_with_lock do |state| record = nil
handler.handle_with_lock do |state|
record = state
state.name = 'new-name' state.name = 'new-name'
end end
expect(state.name).to eq 'new-name' expect(record.reload.name).to eq 'new-name'
end end
it 'raises exception if lock has not been acquired before' do it 'raises exception if lock has not been acquired before' 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