From c8451c21229d650f062a9afa5f1fa33032e8dd7f Mon Sep 17 00:00:00 2001
From: Fredrik Thulin <fredrik@thulin.net>
Date: Thu, 2 Jan 2020 13:23:11 +0100
Subject: [PATCH 1/3] copy edit-secrets from eduid-ops

---
 edit-secrets | 312 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 196 insertions(+), 116 deletions(-)

diff --git a/edit-secrets b/edit-secrets
index 149715e..a82eba5 100755
--- a/edit-secrets
+++ b/edit-secrets
@@ -18,91 +18,10 @@ umask 077
 
 LAST_OUTPUT_FILENAME="/root/.last_edit-secrets_output"
 
-if [[ "x${EDITOR}" != "x" ]]; then
-    declare -r REMOTE_EDITOR="${EDITOR}"
-else
-    declare -r REMOTE_EDITOR='/usr/bin/vim.tiny'
-fi
+test -d /dev/shm && export TMPDIR='/dev/shm'
 
-if [ "x$1" = "x" ]; then
-    echo "Syntax: $0 -l OR fqdn"
-    exit 1
-fi
-
-if [ "x$1" != "x-l" ]; then
-    host=$(echo $1 | sed -e 's!/*$!!')    # remove trailing slashes
-
-    if [ ! -d $host ]; then
-	echo "$0: No host-directory for '$host' found - execute in top-level cosmos dir"
-	exit 1
-    fi
-
-    # Execute this very script, on a remote host
-    TMPFILE=$(mktemp edit-secrets.$$.XXXXXXX)
-    if [ ! -f $TMPFILE ]; then
-	echo "$0: Failed creating temporary file"
-	exit 1
-    fi
-    TMPFILE2=$(mktemp edit-secrets.$$.XXXXXXX)
-    if [ ! -f $TMPFILE2 ]; then
-	echo "$0: Failed creating temporary file"
-	exit 1
-    fi
-
-    trap "rm -f $TMPFILE $TMPFILE2" EXIT
-
-    ssh -t root@$host EDITOR="${REMOTE_EDITOR}" /var/cache/cosmos/repo/edit-secrets -l
-    scp -q root@$host:$LAST_OUTPUT_FILENAME $TMPFILE
-
-    if grep ^"STATUS=UPDATED" $TMPFILE > /dev/null; then
-	# extract the path of the file that should be updated in the Cosmos repo
-        save_to="${host}/overlay/etc/hiera/data/secrets.yaml.asc"
-        mkdir -p "`dirname $save_to`"
-	# extract the GPG output
-	perl -e '$a = 0; while (<>) { $a = 1 if ($_ =~ /-+BEGIN PGP MESSAGE-+/);
-                 print $_ if $a; $a = 0 if ($_ =~ /-+END PGP MESSAGE-+/); }' < $TMPFILE > $TMPFILE2
-
-	if ! grep "END PGP MESSAGE" $TMPFILE2 > /dev/null; then
-	    echo "$0: Failed extracting PGP output from file $TMPFILE into $TMPFILE2"
-	    exit 1
-	fi
-	# use cat to preserve permissions etc.
-	cat $TMPFILE > $save_to
-	git add $save_to
-
-	echo ""
-	echo "$save_to updated"
-	echo ""
-    else
-	echo ""
-	echo "Not updated"
-	echo ""
-    fi
-
-    rm $TMPFILE $TMPFILE2
-
-    exit 0
-fi
-
-#
-# Local execution on a host
-#
-
-SECRETFILE=/etc/hiera/data/secrets.yaml.asc
-GNUPGHOME=/etc/hiera/gpg/
-export GNUPGHOME
-
-GPG=`which gpg2 || true`
-if [ ! -x "$GPG" ]; then
-    GPG=`which gpg || true`
-    if [ ! -x "$GPG" ]; then
-	echo "$0: gpg2 or gpg not found"
-	exit 1
-    fi
-fi
-
-TMPFILE=$(mktemp --tmpdir=/dev/shm)
-TMPFILE2=$(mktemp --tmpdir=/dev/shm)
+TMPFILE=$(mktemp edit-secrets.XXXXXXXXXX)
+TMPFILE2=$(mktemp edit-secrets.XXXXXXXXXX)
 
 if [ ! -f $TMPFILE ]; then
     echo "$TMPFILE"
@@ -117,47 +36,208 @@ fi
 
 trap "rm -f $TMPFILE $TMPFILE2" EXIT
 
-if ! $GPG --list-secret-keys | grep -q ^"sec\s"; then
-    echo "$0: Secret key does not exist (in $GNUPGHOME)."
-    echo ""
-    echo "Generate it with /var/cache/cosmos/model/pre-tasks.d/040hiera-gpg"
-    echo ""
+
+if [[ ! $1 ]]; then
+    # deliberately don't mention the --on-host argument
+    echo "Syntax: $0 fqdn"
     exit 1
 fi
 
-if [ -s $SECRETFILE ]; then
-    $GPG -d $SECRETFILE > $TMPFILE
-fi
 
-cp $TMPFILE $TMPFILE2
-sensible-editor $TMPFILE
-rm -f ${TMPFILE}~ ${TMPFILE2}~
+function edit_copy_and_commit()
+{
+    #
+    # This code runs on the administrators local machine
+    #
+    local host=$1
 
-echo ""
-echo ""
+    if [[ ${EDITOR} ]]; then
+	declare -r REMOTE_EDITOR="${EDITOR}"
+    else
+	declare -r REMOTE_EDITOR='/usr/bin/vim.tiny'
+    fi
 
-status=0
-cmp -s $TMPFILE $TMPFILE2 || status=1
-if [ $status -eq 0 ]; then
-    (
-	echo "STATUS=NOT_CHANGED"
-    )  > $LAST_OUTPUT_FILENAME
-    echo ""
-    echo "$0: No changes detected"
-else
-    # figure out this hosts gpg key id
-    recipient=$($GPG --list-secret-key | grep ^sec | head -1 | awk '{print $2}' | cut -d / -f 2)
+    # Execute this script, on a remote host
+    ssh -t root@"${host}" EDITOR="${REMOTE_EDITOR}" /var/cache/cosmos/repo/edit-secrets --on-host
+    scp -q root@"${host}:${LAST_OUTPUT_FILENAME}" ${TMPFILE}
 
-    save_to="`hostname --fqdn`/overlay${SECRETFILE}"
-    echo ""
-    (
-	echo "STATUS=UPDATED"
+    local save_to
+    if grep ^"STATUS=UPDATED" $TMPFILE > /dev/null; then
+        save_to="${host}/overlay/etc/hiera/data/secrets.yaml.asc"
+
+	# extract the GPG output
+	perl -e '$a = 0; while (<>) { $a = 1 if ($_ =~ /-+BEGIN PGP MESSAGE-+/);
+                 print $_ if $a; $a = 0 if ($_ =~ /-+END PGP MESSAGE-+/); }' < $TMPFILE > $TMPFILE2
+
+	if ! grep "END PGP MESSAGE" $TMPFILE2 > /dev/null; then
+	    echo "$0: Failed extracting PGP output from file $TMPFILE into $TMPFILE2"
+	    exit 1
+	fi
+    elif grep ^"STATUS=EYAML_UPDATED" $TMPFILE > /dev/null; then
+        save_to="${host}/overlay/etc/hiera/data/local.eyaml"
+
+	# extract the eyaml output
+	perl -e '$a = 0; while (<>) { $a = 1 if ($_ =~ /^---$/);
+                 print $_ if $a }' < $TMPFILE > $TMPFILE2
+
+	if ! grep "^---$" $TMPFILE2 > /dev/null; then
+	    echo "$0: Failed extracting yaml output from file $TMPFILE into $TMPFILE2"
+	    exit 1
+	fi
+    else
 	echo ""
-    ) > $LAST_OUTPUT_FILENAME
-    $GPG --output - --armor --recipient $recipient --sign --encrypt $TMPFILE >> $LAST_OUTPUT_FILENAME
+	echo "Not updated"
+	echo ""
+
+	exit 0
+    fi
+
+    # use cat to preserve permissions etc.
+    mkdir -p "`dirname ${save_to}`"
+    cat $TMPFILE2 > "${save_to}"
+    git add "${save_to}"
+
+    if grep ^"STATUS=EYAML_UPDATED" $TMPFILE > /dev/null; then
+	git diff --cached "${save_to}"
+    fi
+
     echo ""
-    echo "GPG output saved in $LAST_OUTPUT_FILENAME - save it in Cosmos as"
+    echo "$save_to updated"
     echo ""
-    echo "  $save_to"
+
+    exit 0
+}
+
+function edit_file_on_host() {
+    #
+    # Local execution on a host
+    #
+
+    local SECRETFILE=/etc/hiera/data/secrets.yaml.asc
+    local EYAMLFILE=/etc/hiera/data/local.eyaml
+
+    if [ -f "${EYAMLFILE}" ]; then
+	edit_eyaml_file ${EYAMLFILE}
+    elif [ -f "${SECRETFILE}" ]; then
+	edit_gpg_file ${SECRETFILE}
+    elif [ -f /etc/hiera/eyaml/public_certkey.pkcs7.pem ]; then
+	# default to eyaml if the key exists and none of the secrets-file above exist
+	touch ${EYAMLFILE}
+	edit_eyaml_file ${EYAMLFILE}
+    fi
+}
+
+function edit_gpg_file()
+{
+    local SECRETFILE=$1
+
+    GNUPGHOME=/etc/hiera/gpg/
+    export GNUPGHOME
+
+    local GPG=`which gpg2 || true`
+    if [ ! -x "$GPG" ]; then
+	GPG=`which gpg || true`
+	if [ ! -x "$GPG" ]; then
+	    echo "$0: gpg2 or gpg not found"
+	    exit 1
+	fi
+    fi
+
+    if ! $GPG --list-secret-keys | grep -q ^"sec\s"; then
+	echo "$0: Secret key does not exist (in $GNUPGHOME)."
+	echo ""
+	echo "Generate it with /var/cache/cosmos/model/pre-tasks.d/040hiera-gpg"
+	echo ""
+	exit 1
+    fi
+
+    if [ -s $SECRETFILE ]; then
+	$GPG -d $SECRETFILE > $TMPFILE
+    fi
+
+    cp $TMPFILE $TMPFILE2
+    sensible-editor $TMPFILE
+    rm -f ${TMPFILE}~ ${TMPFILE2}~
+
     echo ""
+    echo ""
+
+    local status=0
+    cmp -s $TMPFILE $TMPFILE2 || status=1
+    if [ $status -eq 0 ]; then
+	(
+	    echo "STATUS=NOT_CHANGED"
+	)  > $LAST_OUTPUT_FILENAME
+	echo ""
+	echo "$0: No changes detected"
+    else
+	# figure out this hosts gpg key id
+	if lsb_release -r | grep -q 18.04; then
+	    recipient=$($GPG --list-secret-keys | grep -A1 '^sec' | tail -1 | awk '{print $1}')
+	else
+	    recipient=$($GPG --list-secret-key | grep ^sec | head -1 | awk '{print $2}' | cut -d / -f 2)
+	fi
+
+	save_to="`hostname --fqdn`/overlay${SECRETFILE}"
+	echo ""
+	(
+	    echo "STATUS=UPDATED"
+	    echo ""
+	) > $LAST_OUTPUT_FILENAME
+	$GPG --output - --armor --recipient $recipient --sign --encrypt $TMPFILE >> $LAST_OUTPUT_FILENAME
+	echo ""
+	echo "GPG output saved in $LAST_OUTPUT_FILENAME - save it in Cosmos as"
+	echo ""
+	echo "  $save_to"
+	echo ""
+    fi
+}
+
+function edit_eyaml_file()
+{
+    local EYAMLFILE=$1
+
+    local FQDN=$(hostname --fqdn)
+    local privkey='/etc/hiera/eyaml/private_key.pkcs7.pem'
+    local pubkey='/etc/hiera/eyaml/public_certkey.pkcs7.pem'
+    for f in $privkey $pubkey; do
+	test -f "${f}" || { echo "$0: eyaml key file ${f} not found"; exit 1; }
+    done
+
+    # save source file for comparision afterwards
+    cp "${EYAMLFILE}" "${TMPFILE}"
+    eyaml edit --pkcs7-private-key "${privkey}" --pkcs7-public-key "${pubkey}" "${EYAMLFILE}"
+
+    local status=0
+    cmp -s "${EYAMLFILE}" $TMPFILE || status=1
+    if [ $status -eq 0 ]; then
+	(
+	    echo "STATUS=NOT_CHANGED"
+	)  > $LAST_OUTPUT_FILENAME
+	echo ""
+	echo "$0: No changes detected"
+    else
+	echo ""
+	(
+	    echo "STATUS=EYAML_UPDATED"
+	    echo ""
+	) > $LAST_OUTPUT_FILENAME
+	cat "${EYAMLFILE}" >> $LAST_OUTPUT_FILENAME
+    fi
+}
+
+
+if [[ $1 == '--on-host' ]]; then
+    edit_file_on_host
+else
+    host=$(echo $1 | sed -e 's!/*$!!')    # remove trailing slashes
+
+    if [ ! -d $host ]; then
+	echo "$0: No host-directory for '$host' found - execute in top-level cosmos dir"
+	exit 1
+    fi
+
+    edit_copy_and_commit $host
 fi
+
+exit 0

From d12f6297eddfc2b0d0d015f5dee157bbf3665465 Mon Sep 17 00:00:00 2001
From: Kristofer Hallin <kristofer@sunet.se>
Date: Mon, 14 Sep 2020 10:02:20 +0200
Subject: [PATCH 2/3] Support Ubuntu 20 as well for edit-secrets.

---
 edit-secrets | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/edit-secrets b/edit-secrets
index a82eba5..e10ad3b 100755
--- a/edit-secrets
+++ b/edit-secrets
@@ -172,7 +172,7 @@ function edit_gpg_file()
 	echo "$0: No changes detected"
     else
 	# figure out this hosts gpg key id
-	if lsb_release -r | grep -q 18.04; then
+	if lsb_release -r | grep -qE '(18|20).04'; then
 	    recipient=$($GPG --list-secret-keys | grep -A1 '^sec' | tail -1 | awk '{print $1}')
 	else
 	    recipient=$($GPG --list-secret-key | grep ^sec | head -1 | awk '{print $2}' | cut -d / -f 2)

From a7d0a189da5c4c465aa1f2b60dc8daedab71679b Mon Sep 17 00:00:00 2001
From: Patrik Lundin <patlu@sunet.se>
Date: Wed, 18 Jan 2023 13:50:09 +0100
Subject: [PATCH 3/3] Work around broken hiera-eyaml on 22.04

This can be removed once the linked bug report is solved.

Idea from, and implementation reviewed by, @fredrikt
---
 edit-secrets | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/edit-secrets b/edit-secrets
index e10ad3b..b4d816c 100755
--- a/edit-secrets
+++ b/edit-secrets
@@ -43,6 +43,35 @@ if [[ ! $1 ]]; then
     exit 1
 fi
 
+function patch_broken_eyaml {
+    #
+    # Ubuntu 22.04 (jammy) has a broken hiera-eyaml package, a bug report
+    # exists here: https://bugs.launchpad.net/ubuntu/+source/hiera-eyaml/+bug/1974059
+    #
+
+    if [ "$(lsb_release -cs)" == "jammy" ]; then
+        plugins_file="/usr/share/rubygems-integration/all/gems/hiera-eyaml-3.2.2/lib/hiera/backend/eyaml/plugins.rb"
+        if [ -f $plugins_file ]; then
+            # We only want to try patching the file if it is the known broken version
+            bad_sum="1d0f14765ebcfcdae300d8ac5d715845ef9b283345d19114a23d96161556618f"
+            sum=$(sha256sum $plugins_file | awk '{print $1}')
+            if [ "$sum" == "$bad_sum" ]; then
+                patch --fuzz=0 --directory=/ --strip=0 <<'EOF'
+--- /usr/share/rubygems-integration/all/gems/hiera-eyaml-3.2.2/lib/hiera/backend/eyaml/plugins.rb.orig	2023-01-18 08:20:22.140338419 +0000
++++ /usr/share/rubygems-integration/all/gems/hiera-eyaml-3.2.2/lib/hiera/backend/eyaml/plugins.rb	2023-01-18 08:21:05.654053501 +0000
+@@ -32,6 +32,7 @@
+             specs = Gem::VERSION >= "1.6.0" ? source.latest_specs(true) : source.latest_specs
+
+             specs.each do |spec|
++              spec = spec.to_spec if spec.respond_to?(:to_spec)
+               next if @@plugins.include? spec
+
+               dependency = spec.dependencies.find { |d| d.name == "hiera-eyaml" }
+EOF
+            fi
+        fi
+    fi
+}
 
 function edit_copy_and_commit()
 {
@@ -204,6 +233,8 @@ function edit_eyaml_file()
 	test -f "${f}" || { echo "$0: eyaml key file ${f} not found"; exit 1; }
     done
 
+    patch_broken_eyaml
+
     # save source file for comparision afterwards
     cp "${EYAMLFILE}" "${TMPFILE}"
     eyaml edit --pkcs7-private-key "${privkey}" --pkcs7-public-key "${pubkey}" "${EYAMLFILE}"