#!/usr/bin/env bash # Resolve secret placeholders <> 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] 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. <>); 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