diff --git a/live/operator-session/clawdie-join-hive.sh b/live/operator-session/clawdie-join-hive.sh index 6d00f87c..f27eaced 100755 --- a/live/operator-session/clawdie-join-hive.sh +++ b/live/operator-session/clawdie-join-hive.sh @@ -18,6 +18,55 @@ have() { command -v "$1" >/dev/null 2>&1 } +# Read a value into the variable named by $1 without echoing keystrokes. +# Used for the Vaultwarden secret + password so they never appear on screen. +read_secret() { + printf '%s' "$2" + stty -echo 2>/dev/null + read -r "$1" + stty echo 2>/dev/null + echo "" +} + +# Upsert BW_CLIENTID/BW_CLIENTSECRET/BW_PASSWORD into provider.env (root-owned, +# 0600) without leaking secrets through process arguments. The values stay in +# shell variables and a 0600 temp file; provider.env is read and written via mdo +# so the unprivileged operator session can update it. +write_provider_bw() { + _cache="${HOME:-/home/clawdie}/.cache/clawdie" + mkdir -p "$_cache" 2>/dev/null + chmod 0700 "$_cache" 2>/dev/null + _tmp="$(mktemp "${_cache}/joinhive.XXXXXX")" || return 1 + chmod 0600 "$_tmp" 2>/dev/null + + if have mdo; then + mdo -u root cat "$PROVIDER_ENV" >"$_tmp" 2>/dev/null || : + else + cat "$PROVIDER_ENV" >"$_tmp" 2>/dev/null || : + fi + + # Drop any existing BW_* definitions, then append the freshly entered ones. + grep -vE '^(BW_CLIENTID|BW_CLIENTSECRET|BW_PASSWORD)=' "$_tmp" >"${_tmp}.new" 2>/dev/null || : >"${_tmp}.new" + { + printf 'BW_CLIENTID=%s\n' "$BW_CLIENTID" + printf 'BW_CLIENTSECRET=%s\n' "$BW_CLIENTSECRET" + printf 'BW_PASSWORD=%s\n' "$BW_PASSWORD" + } >>"${_tmp}.new" + mv "${_tmp}.new" "$_tmp" + chmod 0600 "$_tmp" 2>/dev/null + + if have mdo; then + mdo -u root cp "$_tmp" "$PROVIDER_ENV" && mdo -u root chmod 0600 "$PROVIDER_ENV" + _rc=$? + else + cp "$_tmp" "$PROVIDER_ENV" && chmod 0600 "$PROVIDER_ENV" + _rc=$? + fi + + rm -f "$_tmp" "${_tmp}.new" 2>/dev/null + return $_rc +} + provider_env_has_bw_creds() { _check='test -f "$1" && grep -Eq "^BW_CLIENTID=.+" "$1" && grep -Eq "^BW_CLIENTSECRET=.+" "$1" && grep -Eq "^BW_PASSWORD=.+" "$1"' @@ -64,14 +113,75 @@ if [ ! -S "$SOCKET" ]; then finish 1 fi -# 2. Vault creds. provider.env is intentionally 0600, so check via mdo when possible. -echo "[2/4] Checking vault credentials..." +# 2. Vault creds + provider keys. provider.env is intentionally 0600 (root), so +# read/write via mdo. If the 3 bootstrap values are absent, prompt for them and +# save them; then pull the provider keys (DeepSeek, etc.) from Vaultwarden. +echo "[2/4] Vault credentials..." +if ! provider_env_has_bw_creds; then + echo "" + echo " No Vaultwarden bootstrap credentials found." + echo " Enter the 3 values, or press Enter at the first prompt to skip." + echo "" + printf " BW_CLIENTID: " + read -r BW_CLIENTID + if [ -n "${BW_CLIENTID:-}" ]; then + read_secret BW_CLIENTSECRET " BW_CLIENTSECRET (hidden): " + read_secret BW_PASSWORD " BW_PASSWORD (hidden): " + if [ -n "${BW_CLIENTSECRET:-}" ] && [ -n "${BW_PASSWORD:-}" ]; then + if write_provider_bw; then + echo " Saved to ${PROVIDER_ENV} (0600)." + else + echo " ERROR: could not write ${PROVIDER_ENV}." + fi + else + echo " Skipped: secret or password was empty." + fi + unset BW_CLIENTSECRET BW_PASSWORD + else + echo " Skipped credential entry." + fi + unset BW_CLIENTID +fi + if provider_env_has_bw_creds; then - echo " provider.env contains Vaultwarden bootstrap credential fields." + echo " Pulling provider keys from Vaultwarden..." + if have clawdie-vault-fetch && have bw && have mdo; then + if mdo -u root clawdie-vault-fetch --bootstrap "$PROVIDER_ENV" --write-env "$PROVIDER_ENV"; then + echo " Provider keys updated (DeepSeek and any others present)." + echo " Restarting colibri daemon to load the new keys..." + if mdo -u root service colibri_daemon restart >/dev/null 2>&1; then + _t=0 + while [ "$_t" -lt 5 ] && [ ! -S "$SOCKET" ]; do + sleep 1 + _t=$(( _t + 1 )) + done + # Confirm the auto-spawned Pi came up (colibri auto-spawn on boot). + if have colibri; then + _p=0 + while [ "$_p" -lt 10 ]; do + if colibri --socket "$SOCKET" status 2>/dev/null | grep -q '"agents":[1-9]'; then + echo " Pi agent is live." + break + fi + sleep 1 + _p=$(( _p + 1 )) + done + [ "$_p" -lt 10 ] || echo " NOTE: no Pi agent yet — check: colibri status" + fi + else + echo " WARNING: daemon restart failed." + echo " Run: mdo -u root service colibri_daemon restart" + fi + else + echo " WARNING: vault fetch did not complete (check network / credentials)." + echo " The manual wizard remains available; keys can be added later." + fi + else + echo " NOTE: clawdie-vault-fetch, bw, or mdo unavailable — skipping key pull." + fi else - echo " WARNING: provider.env is missing, unreadable, or lacks BW_CLIENTID/BW_CLIENTSECRET/BW_PASSWORD." - echo " Vault provisioning will be skipped until the operator adds them." - echo " Edit ${PROVIDER_ENV} and keep it mode 0600, then re-run." + echo " WARNING: provider.env still lacks BW_CLIENTID/BW_CLIENTSECRET/BW_PASSWORD." + echo " Vault provisioning is skipped until they are added." fi # 3. Detect capabilities