#!/usr/bin/env bash # Edit a single attribute of a sops json file # Helps working with multiline strings in json set -euo pipefail print_help() { cat << EOF clerie-sops-edit This script allows editing single secrets in a secrets file by key. is a sops secrets file is one of "edit", "read", "set" and "append" is the key of the secret in the secrets file to modify EOF } if [[ $# != 3 ]]; then print_help exit 1 fi SECRETS_FILE="$1" if [[ ! -f "${SECRETS_FILE}" ]]; then echo "File \"${SECRETS_FILE}\" does not exist" echo print_help exit 1 fi ACTION="$2" if ! echo "edit read set append" | grep -wq "${ACTION}"; then echo "Action \"${ACTION}\" not supported" echo print_help exit 1 fi KEY="$3" KEY_SELECTOR="$(jq -Rsc '[.]' <(echo -n "${KEY}"))" if [[ -n $EDITOR ]]; then EDITOR=vim fi TMP_FILE="$(mktemp)" DECRYPT_ERROR_FILE="$(mktemp)" if ! clerie-sops --decrypt --extract "${KEY_SELECTOR}" "${SECRETS_FILE}" > "${TMP_FILE}" 2> "${DECRYPT_ERROR_FILE}"; then # Ignore that the key does not exist, but fail for all other errors if ! grep -q "component .* not found" "${DECRYPT_ERROR_FILE}"; then cat "${DECRYPT_ERROR_FILE}" exit 1 fi fi TMP_FILE_HASH_BEFORE="$(sha256sum "${TMP_FILE}")" case "${ACTION}" in edit) "${EDITOR}" "${TMP_FILE}" ;; read) cat "${TMP_FILE}" ;; set) cat > "${TMP_FILE}" ;; append) cat >> "${TMP_FILE}" ;; *) echo "Unsupported action" exit 1 ;; esac TMP_FILE_HASH_AFTER="$(sha256sum "${TMP_FILE}")" # Don't write value back when it hasn't changed if [[ "${TMP_FILE_HASH_BEFORE}" == "${TMP_FILE_HASH_AFTER}" ]]; then exit 0 fi JSON_QUOTED_SECRET="$(jq -Rsc '.' "${TMP_FILE}")" rm "${TMP_FILE}" clerie-sops --set "${KEY_SELECTOR} ${JSON_QUOTED_SECRET}" "${SECRETS_FILE}"