Skip to content

Instantly share code, notes, and snippets.

@twolfson
Last active May 21, 2024 07:24
Show Gist options
  • Save twolfson/962b1eb776ce9947a09d4924d91fd8b2 to your computer and use it in GitHub Desktop.
Save twolfson/962b1eb776ce9947a09d4924d91fd8b2 to your computer and use it in GitHub Desktop.
Proof of concept to explore merge conflict resolution with SOPS encoded files for https://github.com/mozilla/sops/issues/52
example.yaml merge=sops-mergetool
[merge "sops-mergetool"]
name = sops-mergetool
driver = ./sops-mergetool.sh %O %A %B %L %P
# TODO: I don't follow internal merge between common ancestors...
recursive = binary
# TODO: Explore this...
# http://stackoverflow.com/q/7403102
# [mergetool "sops-mergetool"]
# cmd = ./sops-mergetool.sh "$LOCAL" "$REMOTE" "$BASE" "0" "$MERGED"

gist-sops-merge-conflict

Proof of concept to explore merge conflict resolution with SOPS encoded files for getsops/sops#52

Getting started

Here are the steps to try out this repo:

# Clone this repo
git clone https://gist.github.com/962b1eb776ce9947a09d4924d91fd8b2.git gist-sops-merge-conflict
cd gist-sops-merge-conflict

# Install our PGP key
#   Same as https://github.com/mozilla/sops/blob/5bf336baa822821c729278e43440a93816b0d53c/tests/sops_functional_tests_key.asc
gpg --import sops_key.asc

# Append `.gitconfig` to local `.git/config`
cat .gitconfig >> .git/config

# Try out our conflicting branches
git checkout -B conflict first && git checkout master -- .gitattributes sops-mergetool.sh && git reset && git merge second

Brainstorm notes

Creation of this repo

These are the steps we took to create this repo:

  • Installed PGP key: gpg --import sops_key.asc
  • Created secret file: sops example.yaml --pgp '1022 470D E3F0 BC54 BC6A B62D E055 50BC 07FB 1A0A
    • Contents: foo: foo\nbar: bar
  • Created 2 conflicting branches:
    • git checkout -B first master && sops example.yaml && git add example.yaml && git commit -m "First commit" && git checkout -
      • Content: foo: baz\nbar: bar
    • git checkout -B second master && sops example.yaml && git add example.yaml && git commit -m "Second commit" && git checkout -
      • Content: foo: foo\nbar: baz
  • Try out our conflicting branches
    • git checkout -B conflict first && git checkout master -- . && git checkout HEAD -- example.yaml && git reset && git merge second
foo: ENC[AES256_GCM,data:9l9h,iv:c/QuxSHYuqV4DWLbMMg1MKEKVbsP14sKFYChHSjxJeU=,tag:EDyqP6ckK0aRhE/XcNt6WQ==,type:str]
bar: ENC[AES256_GCM,data:mrM5,iv:8ocfzBl1lSJRfnptLnhV/CS8DeEjMzJdkJRPNUQOo1w=,tag:TE3ynvau958b+b/MeT3upw==,type:str]
sops:
mac: ENC[AES256_GCM,data:eiKgBSVnGKMIMvLKYees7Q74MXCw+XYSjjOXIWuyJfRuHTNU8dFsKjBhgZBL6RHqu4M5LkzS0MAfg0l9GMV1obnnzD0noht8N/Ge3PQ8QXf2aYYsciDsmBkGksQHC2XWHLF7eheLuicHlyZ2S73i+VAs/gOBywwXR+59x58Vntc=,iv:UlCCFAdOs1HuGrya8gCeoWnW8xj4Q2IarmRxbkwPV5I=,tag:z7l7aYnRqWdfL9wnPXDr8w==,type:str]
version: 1.7
kms:
- arn: ''
pgp:
- fp: 1022470DE3F0BC54BC6AB62DE05550BC07FB1A0A
created_at: '2016-04-29T05:55:32Z'
enc: |
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1
hIwDEEVDpnzXnMABA/4wzl/o5TRSXb7/jKK1RjoTTjOhiO0MNJWBgS+UKpoPr5qm
wGPLW51r83EPSPLxVJ+axKIvCiuWCFf6al0BWxNzdL2NhNqicE5Tmx8ohOXXiDZh
wiGPmXbPYVZCl1qu64OBdSywZJbFNUrEOhtQo5o+wnJLGJb5w+/Ly1TzGV6FidJc
AR8WnYfkk1INAsWW5WzLDSmNq8m+0ss51OKZZHl6nOzhJqtT54sdX8uDf52da1jH
pNC6FrzFYWmmTBGKoSBlnVLWp+MCNK/O0LDXc20DYKhcPg9qfG7Bpi0/ZoE=
=cTai
-----END PGP MESSAGE-----
lastmodified: '2016-04-29T06:05:29Z'
attention: This section contains key material that should only be modified with
extra care. See `sops -h`.
unencrypted_suffix: _unencrypted
#!/usr/bin/env bash
# Exit on first error and verify variables have been set/passed via CLI
set -e
set -u
# Rename our variables to friendlier equivalents
# https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver
ancestor="$1"; current="$2"; other="$3"; conflict_size_marker="$4"; result="$5"
# Resolve our default mergetool
mergetool="$(git config --get merge.tool)"
if test "$mergetool" = ""; then
echo "No default \`merge.tool\` was set for \`git\`. Please set one via \`git config --set merge.tool <tool>\`" 1>&2
exit 1
fi
# Decrypt our input files
# TODO: Delete temporary files on `trap`
# TODO: Should these be located in `/tmp` or locally?
# TODO: Match extension of original file for both `--input-type` and `decrypted` filename
current_decrypted="$(mktemp --tmpdir tmp_CURRENT_XXXXXXXXXX.yaml)"
other_decrypted="$(mktemp --tmpdir tmp_OTHER_XXXXXXXXXX.yaml)"
result_decrypted="$(mktemp --tmpdir tmp_RESULT_XXXXXXXXXX.yaml)"
sops --input-type yaml --decrypt "$ancestor" > "$result_decrypted"
sops --input-type yaml --decrypt "$current" > "$current_decrypted"
sops --input-type yaml --decrypt "$other" > "$other_decrypted"
# Use our mergetool
"$mergetool" "$current_decrypted" "$result_decrypted" "$other_decrypted"
# Re-encrypt content
# TODO: We need a SOPS method to replace file contents entirely but preserve keys
echo "Result:"
cat "$result_decrypted"
-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v1
lQHYBFYWi4IBBADQCJUOJC3UOFtH2CTL0z1q+MiqX0/nDWCT+/HcmopzAv4g6nC4
cYNohy2wImR4pLR2IoYdBBzV8iH/E030SSuY+KkO2WAA1QqyJChglrfIlC7VZL+R
/iA6IijQod6uhDUqjDrGVXQUWdEsFRyTjnH7wFiXCQz+Y9lgSMYhP63owwARAQAB
AAP+MJ+w5ytBovbBLxuwDgwDsPsRO/EnJeQUjMI4l81vSs6KQ3tIeXPeuRHPdfmz
7hbhLzOGkUWiz8bWd141vEFV9PFMfGUU4U4lxUT+fdCFdH7gcmfLeCcryeKvmORo
z8hlb/3rIpSXcdDVxA0hARsohZqqeIAVurzZC51BLIxL+uECAOAAEoVwJtb3hJDR
w9eVEqA8vtI80Y709Bu26uDaDO12XdPg80PQvKbJgV2W37LFil8HfUwl0eFVEvgR
sO9cDIkCAO3AlrDE/pva5okDmuy9N14v5wnOQk/ibGOKmvuVSkv0LCiSgSZCvQFI
w2+sxau3IEWbQCI1pDGzDjRQZt0Hb+sB/2+H5lDzh25XUTmNfHPWLob/4amPjaRf
NWGnVSBbXamA/q/dJnt3odNuUFZ1jBhFGrcDzjYPztk69cDhlmJY/TCow7RVU09Q
UyBGdW5jdGlvbmFsIFRlc3RzIChodHRwczovL2dpdGh1Yi5jb20vbW96aWxsYS9z
b3BzLykgPHVsZnIrc29wc3Rlc3RzQG1vemlsbGEuY29tPoi3BBMBCAAhBQJWFouC
AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJEOBVULwH+xoKn6cD/RcsXBkD
afH1kscS2zxhOeEqZiV8J+T3M2ZCrw1gEDn8tWyVdy/O5hwwOKVf10dqrXiKG9ld
3UeokljIhOpGE4izwTQQvE2O/ACdb70kp6BgBUpGsGHU0q+3/wCbDPJjtp4EqzwO
36LzLbaMZyrw0unTSR96sYRuEonuaxRKMwNZnQHYBFYWi4IBBACue2Pc46G2Hki2
eVc5K7uroCTCsOf86WMX36c/jqTnXXsoaKPt3TrGoGo7w3fJvZfdTOseRzuoLVPd
Rel6npyTzvMzajDKOPL/DeVeleT8sn/GKeJwS9cqDxUH6ytZ4fo5nuUM/IGeRXSD
sK9Ri6gWytX7eRflXk0dySVuY5KeXwARAQABAAP+KG6CWRTMi8mfut0KV76pGd+d
tRnOYD5qzoTumh1BXDW+zMHWvs9lh9JzW47ziqWq88aXsyf5jIKYbO1+6YGosXt8
mpc7JFxCthwDWcEGs3J6lSgjlNnsXVlHNwJB74Z/6nmRqVbLUBr2TuuCC+DvWIR2
EP5i5PmwOp4dEdd/NE0CAMZJFrIT69YAXsxyE+6mP6IWYeAvBYPDU1KiHMt/unWk
JPLeiVSoE/AdvNouJJVadoCLO8uRS6dH9wg+j5zlUVsCAOFEn3LX1mGMIx0F3AFq
EfHkNcrWwhWTAy+Sv4pK12xpwN4Fb92/aeD8BSuIQeyZI2HsmCPuiPud1m6lAqe+
Uk0B/2QiApmJOCBeqhXeJV5CaxDebaPKV0UVBsMLORnmAWRNBZ3onzU/XJYP5U5F
zhVfjg3smzHXD/vkfzO0xUqVfiGfUYifBBgBCAAJBQJWFouCAhsMAAoJEOBVULwH
+xoKz18D/2rLxAacpnu+qfKVUNdq+xQAlBF4Tt1xgmRayuYSI0ougvxKwyMFeuXj
sZlaMHbqJX6TpOiFU8FvMU8syhBgWNYYq/3JNKw9GVDabO5Ggbluup/q1/uJHO1y
v8bK3sq5s580DSaWamLgSLwl3UfCnL3Qa0XDT6SoY1L/Wzr1iW+9
=zqxY
-----END PGP PRIVATE KEY BLOCK-----
@zionyx
Copy link

zionyx commented Oct 11, 2021

Something worth fixing:

In the last command:

git checkout -B conflict first && git checkout master -- sops-mergetool.sh && git reset && git merge second

Several issues:

  1. conflict first is not a valid branch name. Try git checkout -B conflict/first
  2. git merge second only works when second was checked out before, instead, try git merge origin/second

Thanks for this POC.

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