Files
jiu/deploy/render-env.sh
T
wangjia 8fc24b5d36 chore(deploy): 移除退役的 ed25519/HMAC license 死配置
兑换券改造后运行时已不读签名相关 env,清理 production.env.template
的 LICENSE_HMAC_SECRET / LICENSE_ED25519_* 三项,并从 render-env.sh
的 SECRET_KEYS 去掉对应密钥(渲染 env 时不再白拉 Bitwarden)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-19 14:04:06 +08:00

117 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# render-env.sh — 从 Bitwarden 渲染 jiu 的 production.env(方案一)
#
# 配置基底 = production.env.template(非密钥项的权威来源,随仓库维护)。
# 密钥 = 从 Bitwarden 条目 DB_PASSWORD 的同名字段按需取,Mac 上不常驻明文。
#
# 用法:
# sh deploy/render-env.sh --check # 只校验:4 个密钥都能从金库取到、长度非空
# sh deploy/render-env.sh --print # 渲染到 stdout 预览(密钥打码,可安全粘贴)
# sh deploy/render-env.sh --out FILE # 渲染到指定文件(含明文,慎用,自负保管)
# sh deploy/render-env.sh --deploy # 渲染→scp 到 EC2→重启 jiu→健康检查→删本地临时文件
#
# 前提:rbw 已 unlock。
set -euo pipefail
# ---- 可配置项 ----
RBW="${RBW_BIN:-/opt/homebrew/bin/rbw}"
BW_ITEM="${JIU_BW_ITEM:-jiu db password}" # 存放 jiu 密钥字段的 Bitwarden 条目
SECRET_KEYS="DATABASE_DSN JWT_SECRET DB_PASSWORD"
EC2_HOST="${EC2_HOST:-18.136.60.128}"
EC2_USER="${EC2_USER:-ec2-user}"
EC2_KEY="${EC2_KEY:-$HOME/.ssh/wangjia.pem}"
REMOTE_ENV="/opt/jiu/config/production.env"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
TEMPLATE="$SCRIPT_DIR/production.env.template"
# ---- 工具函数 ----
is_secret() {
case " $SECRET_KEYS " in *" $1 "*) return 0;; *) return 1;; esac
}
require_unlocked() {
if ! "$RBW" unlocked >/dev/null 2>&1; then
echo "render-env: 金库未解锁,请先运行: rbw unlock" >&2
exit 1
fi
}
# 渲染:逐行读模板,密钥行用金库值替换。$1=mask 时密钥打码。
render() {
local mask="${1:-}"
local line key val
while IFS= read -r line || [ -n "$line" ]; do
case "$line" in
''|\#*) printf '%s\n' "$line"; continue ;;
esac
key="${line%%=*}"
if is_secret "$key"; then
val="$("$RBW" get --field "$key" "$BW_ITEM")"
if [ -z "$val" ]; then
echo "render-env: 金库条目 '$BW_ITEM' 的字段 '$key' 为空" >&2
exit 1
fi
if [ "$mask" = "mask" ]; then
printf '%s=<%d 字符·已打码>\n' "$key" "${#val}"
else
printf '%s=%s\n' "$key" "$val"
fi
else
printf '%s\n' "$line"
fi
done < "$TEMPLATE"
}
# ---- 主流程 ----
[ -f "$TEMPLATE" ] || { echo "render-env: 找不到模板 $TEMPLATE" >&2; exit 1; }
MODE="${1:---print}"
require_unlocked
case "$MODE" in
--check)
for k in $SECRET_KEYS; do
v="$("$RBW" get --field "$k" "$BW_ITEM")"
printf ' %-22s %s\n' "$k" "$([ -n "$v" ] && echo "OK (${#v} 字符)" || echo "缺失 ❌")"
done
;;
--print)
render mask
;;
--out)
OUT="${2:?用法: render-env.sh --out <文件路径>}"
umask 077
render > "$OUT"
echo "render-env: 已写入 $OUT(含明文,注意保管)"
;;
--deploy)
TMP="$(mktemp -t jiu-prod-env)"
trap 'rm -f "$TMP"' EXIT
umask 077
render > "$TMP"
echo "render-env: 已本地渲染(临时文件,退出即删)"
echo "render-env: 上传到 $EC2_USER@$EC2_HOST:$REMOTE_ENV"
scp -i "$EC2_KEY" "$TMP" "$EC2_USER@$EC2_HOST:/tmp/production.env.new"
ssh -i "$EC2_KEY" "$EC2_USER@$EC2_HOST" bash <<REMOTE
set -e
mkdir -p /opt/jiu/config
mv /tmp/production.env.new "$REMOTE_ENV"
chmod 600 "$REMOTE_ENV"
sudo systemctl restart jiu
sleep 3
curl -sf http://localhost:8080/health >/dev/null && echo " 健康检查通过 ✅" || { echo " 健康检查失败 ❌"; exit 1; }
REMOTE
echo "render-env: 部署完成,EC2 上的 production.env 已更新并重启"
;;
*)
echo "未知参数: $MODE" >&2
sed -n '2,16p' "$0" >&2
exit 1
;;
esac