Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cfeb8f0bba |
@@ -1,30 +0,0 @@
|
||||
# 一次性:把 Android release keystore 从 CI secret 导出为 artifact,便于本地/Bitwarden 备份。
|
||||
# 用完务必删除:① 本 workflow 文件;② 跑出来的这次 run 的 artifact(含密钥)。
|
||||
# 触发:Forgejo 网页 → Actions → Export Keystore → Run workflow(手动)。
|
||||
name: Export Keystore
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
export:
|
||||
runs-on: mac
|
||||
steps:
|
||||
- name: Restore keystore from secret
|
||||
env:
|
||||
ANDROID_KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p out
|
||||
# 原始 base64(方便直接粘进 Bitwarden Secure Note)
|
||||
printf '%s' "$ANDROID_KEYSTORE_BASE64" > out/keystore.b64.txt
|
||||
# 解码回二进制 keystore
|
||||
printf '%s' "$ANDROID_KEYSTORE_BASE64" | base64 --decode > out/jiu-release.jks
|
||||
echo "base64 长度: $(wc -c < out/keystore.b64.txt)"
|
||||
echo "jks 字节数: $(wc -c < out/jiu-release.jks)"
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: keystore-backup
|
||||
path: out/
|
||||
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.19] - 2026-06-07
|
||||
|
||||
### 改进
|
||||
- 优化 Android 构建与部署流程(CI/CD 内部调整),功能与界面无变化
|
||||
|
||||
## [1.0.18] - 2026-06-06
|
||||
|
||||
### 新功能
|
||||
|
||||
Executable
+116
@@ -0,0 +1,116 @@
|
||||
#!/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:-DB_PASSWORD}" # 存放 jiu 密钥字段的 Bitwarden 条目
|
||||
SECRET_KEYS="DATABASE_DSN JWT_SECRET LICENSE_HMAC_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
|
||||
@@ -20,20 +20,23 @@ echo "==> compile-android: version=${VER} build=${BUILD}"
|
||||
# Sync Flutter pubspec version (BSD sed on macOS)
|
||||
sed -i '' "s/^version:.*/version: ${VER}+${BUILD}/" client/pubspec.yaml
|
||||
|
||||
# --- release 签名:从 CI secrets 还原 keystore 与 key.properties ---
|
||||
if [ -n "${ANDROID_KEYSTORE_BASE64:-}" ]; then
|
||||
echo "==> compile-android: configuring release signing"
|
||||
KEYSTORE_PATH="$(pwd)/client/android/jiu-release.jks"
|
||||
echo "${ANDROID_KEYSTORE_BASE64}" | base64 --decode > "${KEYSTORE_PATH}"
|
||||
cat > client/android/key.properties <<EOF
|
||||
# --- release 签名(强制):从 CI secrets 还原 keystore 与 key.properties ---
|
||||
# 必须 release 签名。缺任一签名 secret 直接失败,绝不回退 debug:
|
||||
# debug 包用公开调试密钥签名,不能正式分发,也无法与正式版互相覆盖升级。
|
||||
: "${ANDROID_KEYSTORE_BASE64:?缺少 ANDROID_KEYSTORE_BASE64:未配置 Android release 签名,构建中止(不回退 debug)}"
|
||||
: "${ANDROID_KEYSTORE_PASSWORD:?缺少 ANDROID_KEYSTORE_PASSWORD:未配置 Android release 签名,构建中止}"
|
||||
: "${ANDROID_KEY_ALIAS:?缺少 ANDROID_KEY_ALIAS:未配置 Android release 签名,构建中止}"
|
||||
: "${ANDROID_KEY_PASSWORD:?缺少 ANDROID_KEY_PASSWORD:未配置 Android release 签名,构建中止}"
|
||||
|
||||
echo "==> compile-android: configuring release signing"
|
||||
KEYSTORE_PATH="$(pwd)/client/android/jiu-release.jks"
|
||||
echo "${ANDROID_KEYSTORE_BASE64}" | base64 --decode > "${KEYSTORE_PATH}"
|
||||
cat > client/android/key.properties <<EOF
|
||||
storeFile=${KEYSTORE_PATH}
|
||||
storePassword=${ANDROID_KEYSTORE_PASSWORD}
|
||||
keyAlias=${ANDROID_KEY_ALIAS}
|
||||
keyPassword=${ANDROID_KEY_PASSWORD}
|
||||
EOF
|
||||
else
|
||||
echo "==> compile-android: WARNING — no ANDROID_KEYSTORE_BASE64, falling back to debug signing"
|
||||
fi
|
||||
|
||||
# Build APK (universal, all ABIs — simplest for sideload download)
|
||||
cd client
|
||||
|
||||
Reference in New Issue
Block a user