summaryrefslogtreecommitdiff
path: root/vault-merge.sh
diff options
context:
space:
mode:
authorKumar Damani <damani.kumar@gmail.com>2020-06-10 11:08:08 +0000
committerKumar Damani <damani.kumar@gmail.com>2020-06-10 11:08:08 +0000
commite845b3f431a0ed1e5e8655cf5a126da1a94a0c96 (patch)
treec6d9a6e0c9ce28251ab0b91e9bdacd662ffc8f06 /vault-merge.sh
initial commitHEADmaster
Diffstat (limited to 'vault-merge.sh')
-rwxr-xr-xvault-merge.sh112
1 files changed, 112 insertions, 0 deletions
diff --git a/vault-merge.sh b/vault-merge.sh
new file mode 100755
index 0000000..507a04d
--- /dev/null
+++ b/vault-merge.sh
@@ -0,0 +1,112 @@
+#!/bin/sh
+# vault-merge
+
+# This script handles conflicts generated by attempts to merge encrypted
+# Ansible Vault files.
+# Run `git merge` as usual; when git warns of a merge conflict,
+# 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 (vim).
+
+# Usage:
+# $./vault-merge.sh -p <path/to/the/vault/KEY> <path/to/conflicted/vault>
+
+# First, we ensure we ensure that a suitable e$EDITOR is set
+export EDITOR=vim
+
+# Next, we ensure we are inside the working directory of a git repo.
+
+GIT_ROOT=`git rev-parse --show-toplevel`
+if [ $? != 0 ]; then
+ exit $?
+fi
+
+# Next, we set a default location for a vault password file, and allow the user
+# to override it if desired.
+
+VAULT_PASSWORD_FILE="$GIT_ROOT/vaults/dev-vault-id"
+
+while getopts "p:" opt; do
+ case $opt in
+ p)
+ VAULT_PASSWORD_FILE=$OPTARG
+ ;;
+ \?)
+ # Invalid option (e.g., -p without an argument)
+ exit 1
+ ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+VAULT_OPT="--vault-password-file=$VAULT_PASSWORD_FILE"
+VAULT_FILE=$1
+
+# If no vault has been provided, abort!
+
+if [ -z $VAULT_FILE ]; then
+ echo "Usage: $0 [-p PASSWORD_FILE] VAULT_FILE"
+ exit 1
+fi
+
+# If the password file doesn't exist, we prompt for the password and save it.
+
+if [ ! -e $VAULT_PASSWORD_FILE ]; then
+ read -s -p "Vault Password: " VAULT_PASSWORD
+ echo
+ echo "Remembering password in $VAULT_PASSWORD_FILE"
+ echo $VAULT_PASSWORD > $VAULT_PASSWORD_FILE
+else
+ echo "Using password saved in $VAULT_PASSWORD_FILE"
+fi
+
+# 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 "Merge OK"
+else
+ echo "Merge conflict; opening editor to resolve."
+ $EDITOR $CURRENT
+fi
+
+# Now that we're done, encrypt the file and move it into the repo, and clean up
+# the temporary files (they contain secrets!).
+
+ansible-vault encrypt $VAULT_OPT $CURRENT
+cp $CURRENT $VAULT_FILE
+rm $BASE $CURRENT $OTHER
+
+echo "$VAULT_FILE has been updated."
+echo " (use \"git add $VAULT_FILE\" to mark as resolved)"
+echo " (or re-run this command to retry the merge)"
+exit 0
+