secrets.zsh (3377B)
1 # ---------------------------- Secret Management ------------------------------ 2 3 # direnv integration (must be in interactive shells) 4 if command -v direnv >/dev/null 2>&1; then 5 eval "$(direnv hook zsh)" 6 fi 7 8 # ----------------------------------------------------------------------------- 9 # Secret helpers for Skate + gum. 10 # 11 # Usage: 12 # secret [-g] [-e env] KEY 13 # - By default: uses repo scope if inside a git repo, otherwise global. 14 # - -g forces global scope. 15 # - -e chooses an environment name (default: dev). 16 # 17 # secret-get [-e env] KEY 18 # - Prints the secret to stdout. 19 # - Resolution order: repo DB first (if in a repo), then global DB. 20 # 21 # Notes: 22 # - Skate stores items as: KEY@DB 23 # - DBs are named like: 24 # global.<env> 25 # repo.<repo-slug>.<env> 26 # ----------------------------------------------------------------------------- 27 28 _secrets_repo_slug() { 29 local top remote slug 30 top="$(git -C "$PWD" rev-parse --show-toplevel 2>/dev/null)" || return 1 31 remote="$(git -C "$top" remote get-url origin 2>/dev/null || echo "$top")" 32 33 remote="${remote%.git}" 34 remote="${remote#git@}" 35 remote="${remote#https://}" 36 remote="${remote#http://}" 37 remote="${remote/:/\/}" 38 39 slug="${remote//\//_}" 40 slug="${slug//[^A-Za-z0-9_.-]/_}" 41 slug="${slug%%_}" # strip trailing underscore 42 # Finally change all double underscores to single 43 slug="${slug//__/_}" 44 45 print -r -- "$slug" 46 } 47 48 _secrets_db_global() { print -r -- "global.$1"; } 49 50 _secrets_db_repo() { 51 local env="$1" slug 52 slug="$(_secrets_repo_slug)" || return 1 53 print -r -- "repo.${slug}.${env}" 54 } 55 56 secret() { 57 emulate -L zsh 58 setopt localoptions pipefail 59 60 local env="dev" scope="auto" 61 local OPTIND=1 opt 62 while getopts ":ge:" opt; do 63 case "$opt" in 64 g) scope="global" ;; 65 e) env="$OPTARG" ;; 66 *) echo "Usage: secret [-g] [-e env] KEY" >&2; return 1 ;; 67 esac 68 done 69 shift $((OPTIND-1)) 70 71 local key="$1" 72 [[ -z "$key" ]] && { echo "Usage: secret [-g] [-e env] KEY" >&2; return 1; } 73 74 command -v skate >/dev/null 2>&1 || { echo "Missing: skate" >&2; return 1; } 75 command -v gum >/dev/null 2>&1 || { echo "Missing: gum" >&2; return 1; } 76 77 local db 78 if [[ "$scope" == "global" ]]; then 79 db="$(_secrets_db_global "$env")" 80 else 81 db="$(_secrets_db_repo "$env" 2>/dev/null)" || db="$(_secrets_db_global "$env")" 82 fi 83 84 local value 85 value="$(gum input --password --prompt "Enter secret for $key ($db): ")" || return 1 86 printf "\n" >&2 87 [[ -z "$value" ]] && { echo "Empty value, aborting." >&2; return 1; } 88 89 skate set "${key}@${db}" "$value" 90 echo "Stored ${key}@${db}" 91 } 92 93 secret-get() { 94 emulate -L zsh 95 setopt localoptions pipefail 96 97 local env="dev" 98 local OPTIND=1 opt 99 while getopts ":e:" opt; do 100 case "$opt" in 101 e) env="$OPTARG" ;; 102 *) echo "Usage: secret-get [-e env] KEY" >&2; return 1 ;; 103 esac 104 done 105 shift $((OPTIND-1)) 106 107 local key="$1" 108 [[ -z "$key" ]] && { echo "Usage: secret-get [-e env] KEY" >&2; return 1; } 109 command -v skate >/dev/null 2>&1 || { echo "Missing: skate" >&2; return 1; } 110 111 local repo_db global_db val 112 repo_db="$(_secrets_db_repo "$env" 2>/dev/null)" || repo_db="" 113 global_db="$(_secrets_db_global "$env")" 114 115 if [[ -n "$repo_db" ]] && val="$(skate get "${key}@${repo_db}" 2>/dev/null)"; then 116 print -r -- "$val"; return 0 117 fi 118 skate get "${key}@${global_db}" 119 }