042316ea6a
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
86 lines
2.7 KiB
Bash
86 lines
2.7 KiB
Bash
#!/usr/bin/env bash
|
|
# Resolve secret placeholders <<NAME>> in target file
|
|
# Modes:
|
|
# --secret=NAME=VALUE (non-interactive substitution; can be repeated)
|
|
# --list-unresolved (find <<*>> placeholders, no changes)
|
|
# --skip-unresolved (don't prompt for unresolved; leave + write to .brain-deferred-secrets.txt)
|
|
# (default) interactive prompt for each placeholder not provided via --secret
|
|
#
|
|
# Usage: setup-secrets.sh [--secret=NAME=VALUE ...] [--skip-unresolved | --list-unresolved] <target-file>
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
source "$SCRIPT_DIR/common.sh"
|
|
|
|
declare -A secrets=()
|
|
skip_unresolved=0
|
|
list_only=0
|
|
target=""
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--secret=*)
|
|
kv="${1#--secret=}"
|
|
name="${kv%%=*}"
|
|
value="${kv#*=}"
|
|
secrets["$name"]="$value"
|
|
;;
|
|
--skip-unresolved) skip_unresolved=1 ;;
|
|
--list-unresolved) list_only=1 ;;
|
|
*) target="$1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
[ -n "$target" ] || { log_error "Target file required"; exit 1; }
|
|
[ -f "$target" ] || { log_error "Target not found: $target"; exit 1; }
|
|
|
|
# Find all placeholders (e.g. <<MAGIC_API_KEY>>); uppercase-only names.
|
|
placeholders=$(grep -oE '<<[A-Z_][A-Z0-9_]*>>' "$target" 2>/dev/null | sort -u || true)
|
|
|
|
if [ "$list_only" -eq 1 ]; then
|
|
if [ -z "$placeholders" ]; then
|
|
log_info "No unresolved placeholders in $target"
|
|
else
|
|
log_info "Unresolved placeholders in $target:"
|
|
echo "$placeholders"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
deferred_file="$(dirname "$target")/.brain-deferred-secrets.txt"
|
|
deferred=""
|
|
|
|
for p in $placeholders; do
|
|
name="${p#<<}"
|
|
name="${name%>>}"
|
|
|
|
if [ -n "${secrets[$name]:-}" ]; then
|
|
value="${secrets[$name]}"
|
|
# sed-replace via temp + mv (Windows-safe; avoids sed -i portability issues)
|
|
sed "s|<<$name>>|$value|g" "$target" > "$target.tmp"
|
|
mv "$target.tmp" "$target"
|
|
log_info "Resolved <<$name>>"
|
|
elif [ "$skip_unresolved" -eq 1 ]; then
|
|
deferred="$deferred$name\n"
|
|
log_warn "Skipped <<$name>> (deferred)"
|
|
else
|
|
# Interactive prompt (manual usage; tests always pass --secret or --skip)
|
|
printf "Enter value for <<%s>> (or empty to skip): " "$name" >&2
|
|
read -r value
|
|
if [ -n "$value" ]; then
|
|
sed "s|<<$name>>|$value|g" "$target" > "$target.tmp"
|
|
mv "$target.tmp" "$target"
|
|
log_info "Resolved <<$name>>"
|
|
else
|
|
deferred="$deferred$name\n"
|
|
log_warn "Skipped <<$name>>"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ -n "$deferred" ]; then
|
|
printf "%b" "$deferred" > "$deferred_file"
|
|
log_warn "Deferred secrets recorded: $deferred_file"
|
|
fi
|