Skip to content

Commit

Permalink
Fix issue voxpupuli#54 and improve recovery from simple errors
Browse files Browse the repository at this point in the history
  • Loading branch information
sihil committed Nov 21, 2013
1 parent 5ba8297 commit 30a9eab
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 33 deletions.
10 changes: 10 additions & 0 deletions features/edit.feature
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,13 @@ Feature: eyaml editing
And the output should match /\s+key5: DEC::PKCS7\[VALUE5\]\!/
And the output should match /\s+key6: DEC::PKCS7\[VALUE6\]\!/
And the output should match /multi_encryption: DEC::PLAINTEXT\[JAMMY\]\! DEC::PKCS7\[DODGER\]\!/

Scenario: decrypt and reencrypt an eyaml file with multiple new values
Given my EDITOR is set to "./append.sh test_new_values.yaml"
When I run `bash -c 'cp test_input.yaml test_input.eyaml'`
When I run `eyaml -i test_input.eyaml`
When I run `eyaml -d -y test_input.eyaml`
Then the output should match /encrypted_string: DEC::PKCS7\[planet of the apes\]\!/
And the output should match /new_key1: DEC::PKCS7\[new value one\]\!/
And the output should match /new_key2: DEC::PKCS7\[new value two\]\!/
And the output should match /multi_encryption: DEC::PLAINTEXT\[jammy\]\! DEC::PKCS7\[dodger\]!/
5 changes: 5 additions & 0 deletions features/sandbox/append.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash
TMPFILE='mktemp'
cat $2 $1 > $TMPFILE
cp $TMPFILE $2
rm $TMPFILE
2 changes: 2 additions & 0 deletions features/sandbox/test_new_values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
new_key1: DEC::PKCS7[new value one]!
new_key2: DEC::PKCS7[new value two]!
3 changes: 3 additions & 0 deletions lib/hiera/backend/eyaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ class Hiera
module Backend
module Eyaml

class RecoverableError < StandardError
end

VERSION = "1.3.8"

def self.default_encryption_scheme= new_encryption
Expand Down
78 changes: 45 additions & 33 deletions lib/hiera/backend/eyaml/actions/edit_action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'hiera/backend/eyaml/actions/encrypt_action'
require 'hiera/backend/eyaml/options'
require 'hiera/backend/eyaml/parser/parser'
require 'highline/import'

class Hiera
module Backend
Expand All @@ -19,50 +20,61 @@ def self.execute
decrypted_file = Utils.write_tempfile decrypted_input

editor = Utils.find_editor
system editor, decrypted_file
status = $?

raise StandardError, "File was moved by editor" unless File.file? decrypted_file
edited_file = File.read decrypted_file
Utils.secure_file_delete :file => decrypted_file, :num_bytes => [edited_file.length, decrypted_input.length].max
begin
system "#{editor} #{decrypted_file}"
status = $?

raise StandardError, "Editor #{editor} has not exited?" unless status.exited?
raise StandardError, "Editor did not exit successfully (exit code #{status.exitstatus}), aborting" unless status.exitstatus
raise StandardError, "File was moved by editor" unless File.file? decrypted_file
edited_file = File.read decrypted_file

raise StandardError, "Edited file is blank" if edited_file.empty?
raise StandardError, "Editor #{editor} has not exited?" unless status.exited?
raise StandardError, "Editor did not exit successfully (exit code #{status.exitstatus}), aborting" unless status.exitstatus == 0

if edited_file == decrypted_input
Utils.info "No changes detected, exiting"
else
decrypted_parser = Parser::ParserFactory.decrypted_parser
edited_tokens = decrypted_parser.parse(edited_file)
raise StandardError, "Edited file is blank" if edited_file.empty?

# check that the tokens haven't been copy / pasted
used_ids = edited_tokens.find_all{ |t| t.class.name =~ /::EncToken$/ }.map{ |t| t.id }
if used_ids.length != used_ids.uniq.length
raise StandardError, "A duplicate DEC(ID) was found so I don't know how to proceed. This is probably because you copy and pasted a value - if you do this please delete the ID in parentheses"
end
if edited_file == decrypted_input
Utils.info "No changes detected, exiting"
else
decrypted_parser = Parser::ParserFactory.decrypted_parser
edited_tokens = decrypted_parser.parse(edited_file)

# check that the tokens haven't been copy / pasted
used_ids = edited_tokens.find_all{ |t| t.class.name =~ /::EncToken$/ and !t.id.nil? }.map{ |t| t.id }
if used_ids.length != used_ids.uniq.length
raise RecoverableError, "A duplicate DEC(ID) was found so I don't know how to proceed. This is probably because you copy and pasted a value - if you do this please delete the ID in parentheses"
end

# replace untouched values with the source values
edited_denoised_tokens = edited_tokens.map{ |token|
if token.class.name =~ /::EncToken$/ && !token.id.nil?
old_token = tokens[token.id]
if old_token.plain_text.eql? token.plain_text
old_token
# replace untouched values with the source values
edited_denoised_tokens = edited_tokens.map{ |token|
if token.class.name =~ /::EncToken$/ && !token.id.nil?
old_token = tokens[token.id]
if old_token.plain_text.eql? token.plain_text
old_token
else
token
end
else
token
end
else
token
end
}
}

encrypted_output = edited_denoised_tokens.map{ |t| t.to_encrypted }.join
encrypted_output = edited_denoised_tokens.map{ |t| t.to_encrypted }.join

filename = Eyaml::Options[:eyaml]
File.open("#{filename}", 'w') { |file|
file.write encrypted_output
}
filename = Eyaml::Options[:eyaml]
File.open("#{filename}", 'w') { |file|
file.write encrypted_output
}
end
rescue RecoverableError => e
Utils.info e
if agree "Return to the editor to try again?"
retry
else
raise e
end
ensure
Utils.secure_file_delete :file => decrypted_file, :num_bytes => [edited_file.length, decrypted_input.length].max
end

nil
Expand Down

0 comments on commit 30a9eab

Please sign in to comment.