Skip to content

Instantly share code, notes, and snippets.

@exAspArk
Forked from benzado/vault-merge.sh
Last active March 4, 2021 22:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save exAspArk/97b8924b843a9053d34d3cca8f0ef27a to your computer and use it in GitHub Desktop.
Save exAspArk/97b8924b843a9053d34d3cca8f0ef27a to your computer and use it in GitHub Desktop.
A shell script for merging encrypted Ansible vault files in a git repository
#!/bin/sh
###############################################################################
# USAGE:
# > ansible_vault_merge.sh [-p PASSWORD_FILE VAULT_YAML_FILE
# This shell script handles conflicts generated by attempts to merge encrypted
# Ansible Vault files. Run this command to attempt a merge on the unencrypted
# versions of the file. If there are conflicts, you will be given a chance to
# correct them in $EDITOR
# https://gist.github.com/exAspArk/97b8924b843a9053d34d3cca8f0ef27a
###############################################################################
# Ensure we are inside the working directory of a git repo
GIT_ROOT=`git rev-parse --show-toplevel`
if [ $? != 0 ]; then
exit $?
fi
# Allow the user to use custom ansible vault password file with "-p" arg
while getopts "p:" opt; do
case $opt in
p)
VAULT_PASSWORD_FILE=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done
shift $(($OPTIND - 1))
# If no vault has been provided, abort!
VAULT_FILE=$1
if [ -z $VAULT_FILE ]; then
echo "Usage: $0 [-p PASSWORD_FILE] VAULT_YAML_FILE"
exit 1
fi
# Clean before exit
function cleanup {
rm -f $NEW_VAULT_PASSWORD_FILE $BASE $CURRENT $OTHER
echo "\nCleaning successful"
}
trap cleanup EXIT
# If the password file doesn't exist, we prompt for the password and save it
if [ -z "$VAULT_PASSWORD_FILE" ]; then
read -s -p "Vault Password: " VAULT_PASSWORD
NEW_VAULT_PASSWORD_FILE=`mktemp ${VAULT_FILE}.password.XXXX`
VAULT_PASSWORD_FILE=$NEW_VAULT_PASSWORD_FILE
echo "\nRemembering password in $VAULT_PASSWORD_FILE"
echo $VAULT_PASSWORD > $VAULT_PASSWORD_FILE
else
echo "Using password saved in $VAULT_PASSWORD_FILE"
fi
VAULT_OPT="--vault-password-file=$VAULT_PASSWORD_FILE"
# Fetch the base (common ancestor) version of the encrypted vault file, save
# it to a temporary location, and decrypt it. Hat Tip to the git-merge manual
# page for tipping me off to the `git show :1:path` notation
BASE=`mktemp ${VAULT_FILE}.base.XXXX`
git show :1:${VAULT_FILE} > $BASE 2> /dev/null
if [ $? != 0 ]; then
echo "Path '${VAULT_FILE}' does not have any conflicts."
rm $BASE
exit 1
fi
ansible-vault decrypt $VAULT_OPT $BASE || exit $?
# Do the same with the current (branch we are merging INTO) version of the vault
# file
CURRENT=`mktemp ${VAULT_FILE}.current.XXXX`
git show :2:${VAULT_FILE} > $CURRENT 2> /dev/null
ansible-vault decrypt $VAULT_OPT $CURRENT || exit $?
# And finally, with the other (branch we a merging FROM) version of the vault
OTHER=`mktemp ${VAULT_FILE}.other.XXXX`
git show :3:${VAULT_FILE} > $OTHER 2> /dev/null
ansible-vault decrypt $VAULT_OPT $OTHER || exit $?
# Now that we have all three versions decrypted, ask git to attempt the merge
# again. If it fails again due to a conflict, open $EDITOR and let the user
# perform a manual merge
git merge-file $CURRENT $BASE $OTHER
if [ $? == 0 ]; then
echo "\nMerge successful"
else
echo "\nMerge conflict; opening editor to resolve."
$EDITOR $CURRENT
fi
ansible-vault encrypt $VAULT_OPT $CURRENT
cp $CURRENT $VAULT_FILE
echo "File $VAULT_FILE has been updated!"
exit 0
@zyphlar
Copy link

zyphlar commented Mar 4, 2021

In order to get this to work on Linux I had to change #!/bin/sh to #!/bin/bash (the read option doesn't take -s in sh, and functions don't seem very well supported in sh)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment