Commit 5a3a4cd8 authored by Emily Ring's avatar Emily Ring Committed by Ash McKenzie

Prevent locked Terraform states from being deleted

parent 8dcf4b99
...@@ -27,6 +27,8 @@ module Terraform ...@@ -27,6 +27,8 @@ module Terraform
validates :uuid, presence: true, uniqueness: true, length: { is: UUID_LENGTH }, validates :uuid, presence: true, uniqueness: true, length: { is: UUID_LENGTH },
format: { with: HEX_REGEXP, message: 'only allows hex characters' } format: { with: HEX_REGEXP, message: 'only allows hex characters' }
before_destroy :ensure_state_is_unlocked
default_value_for(:uuid, allows_nil: false) { SecureRandom.hex(UUID_LENGTH / 2) } default_value_for(:uuid, allows_nil: false) { SecureRandom.hex(UUID_LENGTH / 2) }
def latest_file def latest_file
...@@ -87,6 +89,13 @@ module Terraform ...@@ -87,6 +89,13 @@ module Terraform
new_version.save! new_version.save!
end end
def ensure_state_is_unlocked
return unless locked?
errors.add(:base, s_("Terraform|You cannot remove the State file because it's locked. Unlock the State file first before removing it."))
throw :abort # rubocop:disable Cop/BanCatchThrow
end
def parse_serial(file) def parse_serial(file)
Gitlab::Json.parse(file)["serial"] Gitlab::Json.parse(file)["serial"]
rescue JSON::ParserError rescue JSON::ParserError
......
---
title: Prevent locked Terraform states from being deleted
merge_request: 50798
author:
type: changed
...@@ -27504,6 +27504,9 @@ msgstr "" ...@@ -27504,6 +27504,9 @@ msgstr ""
msgid "Terraform|You are about to remove the State file %{name}. This will permanently delete all the State versions and history. The infrastructure provisioned previously\twill remain intact, only the state file with all its versions are to be removed. This action is non-revertible." msgid "Terraform|You are about to remove the State file %{name}. This will permanently delete all the State versions and history. The infrastructure provisioned previously\twill remain intact, only the state file with all its versions are to be removed. This action is non-revertible."
msgstr "" msgstr ""
msgid "Terraform|You cannot remove the State file because it's locked. Unlock the State file first before removing it."
msgstr ""
msgid "Test" msgid "Test"
msgstr "" msgstr ""
......
...@@ -27,6 +27,22 @@ RSpec.describe Terraform::State do ...@@ -27,6 +27,22 @@ RSpec.describe Terraform::State do
end end
end end
describe '#destroy' do
let(:terraform_state) { create(:terraform_state) }
let(:user) { terraform_state.project.creator }
it 'deletes when the state is unlocked' do
expect(terraform_state.destroy).to be_truthy
end
it 'fails to delete when the state is locked', :aggregate_failures do
terraform_state.update!(lock_xid: SecureRandom.uuid, locked_by_user: user, locked_at: Time.current)
expect(terraform_state.destroy).to be_falsey
expect(terraform_state.errors.full_messages).to eq(["You cannot remove the State file because it's locked. Unlock the State file first before removing it."])
end
end
describe '#latest_file' do describe '#latest_file' do
let(:terraform_state) { create(:terraform_state, :with_version) } let(:terraform_state) { create(:terraform_state, :with_version) }
let(:latest_version) { terraform_state.latest_version } let(:latest_version) { terraform_state.latest_version }
......
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