feat: secrets recipients list (EGB-283)
This commit is contained in:
parent
14cf86fba9
commit
649aa78063
2 changed files with 72 additions and 0 deletions
51
secrets
51
secrets
|
|
@ -150,6 +150,29 @@ _load_recipients() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Emit "<key>\t<name>" for each recipient in recipients.txt. <name> is the most
|
||||
# recent preceding "# <name>" comment, or empty. Read-only; no validation
|
||||
# (callers that need rails call _load_recipients separately).
|
||||
_recipients_dump() {
|
||||
[ -e "$RECIPIENTS_FILE" ] || return 0
|
||||
local line trimmed name=""
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
trimmed="${line#"${line%%[![:space:]]*}"}"
|
||||
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
|
||||
[ -z "$trimmed" ] && continue
|
||||
case "$trimmed" in
|
||||
'#'*)
|
||||
name="${trimmed#\#}"
|
||||
name="${name#"${name%%[![:space:]]*}"}"
|
||||
;;
|
||||
*)
|
||||
printf '%s\t%s\n' "$trimmed" "$name"
|
||||
name=""
|
||||
;;
|
||||
esac
|
||||
done < "$RECIPIENTS_FILE"
|
||||
}
|
||||
|
||||
derive_project_name() {
|
||||
local explicit="${1:-}"
|
||||
if [ -n "$explicit" ]; then
|
||||
|
|
@ -1954,6 +1977,33 @@ cmd_run() {
|
|||
exit "$rc"
|
||||
}
|
||||
|
||||
cmd_recipients() {
|
||||
resolve_store
|
||||
local sub="${1:-list}"
|
||||
[ $# -gt 0 ] && shift
|
||||
case "$sub" in
|
||||
list) _recipients_list ;;
|
||||
*) die "Unknown recipients subcommand: '$sub'. Usage: secrets recipients [list]" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
_recipients_list() {
|
||||
check_initialized
|
||||
if [ ! -e "$RECIPIENTS_FILE" ]; then
|
||||
check_key
|
||||
echo "recipients: single-key (no $RECIPIENTS_FILE_NAME)"
|
||||
echo " $(get_pubkey)"
|
||||
return 0
|
||||
fi
|
||||
_load_recipients # validates the file (dies on bad key / symlink)
|
||||
local count=0 k n
|
||||
while IFS=$'\t' read -r k n; do count=$((count + 1)); done < <(_recipients_dump)
|
||||
echo "recipients: $count (from $RECIPIENTS_FILE_NAME)"
|
||||
while IFS=$'\t' read -r k n; do
|
||||
if [ -n "$n" ]; then echo " $k ($n)"; else echo " $k"; fi
|
||||
done < <(_recipients_dump)
|
||||
}
|
||||
|
||||
cmd_which() {
|
||||
resolve_store
|
||||
echo "store: $SECRETS_DIR"
|
||||
|
|
@ -2564,6 +2614,7 @@ case "${1:-help}" in
|
|||
rekey) cmd_rekey ;;
|
||||
verify) shift; cmd_verify "$@" ;;
|
||||
migrate) shift; cmd_migrate "$@" ;;
|
||||
recipients) shift; cmd_recipients "$@" ;;
|
||||
which|where|status) cmd_which ;;
|
||||
help|--help|-h) cmd_help ;;
|
||||
*) die "Unknown command: $1. Run 'secrets help' for usage." ;;
|
||||
|
|
|
|||
|
|
@ -55,3 +55,24 @@ make_second_identity() {
|
|||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"symlink"* ]] || false
|
||||
}
|
||||
|
||||
@test "recipients list on a legacy store shows the single derived key" {
|
||||
init_with_remote
|
||||
run "$SECRETS_BIN" recipients list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"single-key"* ]] || false
|
||||
STORE_PUB=$(age-keygen -y "$SECRETS_DIR/key.txt")
|
||||
[[ "$output" == *"$STORE_PUB"* ]] || false
|
||||
}
|
||||
|
||||
@test "recipients list shows names and keys from recipients.txt" {
|
||||
init_with_remote
|
||||
make_second_identity
|
||||
STORE_PUB=$(age-keygen -y "$SECRETS_DIR/key.txt")
|
||||
printf '# alice\n%s\n# bob\n%s\n' "$STORE_PUB" "$BOB_PUB" > "$SECRETS_DIR/recipients.txt"
|
||||
run "$SECRETS_BIN" recipients list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"recipients: 2"* ]] || false
|
||||
[[ "$output" == *"alice"* ]] || false
|
||||
[[ "$output" == *"bob"* ]] || false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue