diff --git a/zsh/zshrc b/zsh/zshrc index 8d625ca..9c44084 100644 --- a/zsh/zshrc +++ b/zsh/zshrc @@ -107,12 +107,35 @@ opc() { [[ -n $value ]] || { print -u2 "opc: empty value for $name; nothing changed"; return 1; } fi # [concealed] makes it a password field; an existing field of that name is updated. - _dotfiles_op sh -c 'op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[concealed]=$2" >/dev/null' \ - opc "$name" "$value" && ops + # op can exit non-zero with "(404) Not Found" after an edit it did save (seen with + # op 2.34.1 and 2.39.0), so its exit code is ignored: the field is read back instead. + _dotfiles_op sh -c ' + clean() { printf "%s" "${1:-(no output)}" | sed "s/^\[ERROR\] [0-9/]* [0-9:]* //"; } + ref="op://$OP_VAULT/$OP_ITEM/$1" + err=$(op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[concealed]=$2" 2>&1 >/dev/null) + if [ "$(op read "$ref" 2>/dev/null)" = "$2" ]; then + printf "opc: saved %s\n" "$ref" >&2 + else + printf "opc: could not save %s\n op said: %s\n check vault, item and service-account write access with: opl\n" \ + "$ref" "$(clean "$err")" >&2 + exit 1 + fi' opc "$name" "$value" && ops } opd() { _dotfiles_env_name "$1" opd || return - _dotfiles_op sh -c 'op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[delete]" >/dev/null' opd "$1" \ + # As in opc, op's exit code is unreliable here: check the item's field labels instead. + _dotfiles_op sh -c ' + clean() { printf "%s" "${1:-(no output)}" | sed "s/^\[ERROR\] [0-9/]* [0-9:]* //"; } + ref="op://$OP_VAULT/$OP_ITEM/$1" + err=$(op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[delete]" 2>&1 >/dev/null) + if ! item=$(op item get "$OP_ITEM" --vault "$OP_VAULT" --format json 2>&1); then + printf "opd: could not re-read %s to confirm the delete\n op said: %s\n" "$ref" "$(clean "$item")" >&2 + exit 1 + elif printf "%s" "$item" | jq -r ".fields[].label" | grep -qxF "$1"; then + printf "opd: could not delete %s\n op said: %s\n" "$ref" "$(clean "$err")" >&2 + exit 1 + fi + printf "opd: deleted %s\n" "$ref" >&2' opd "$1" \ && unset "$1" && ops } opl() {