diff --git a/.gitea/workflows/export-keystore.yml b/.gitea/workflows/export-keystore.yml deleted file mode 100644 index cc49918..0000000 --- a/.gitea/workflows/export-keystore.yml +++ /dev/null @@ -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/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 1388e0a..0c3a805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 ### 新功能 diff --git a/deploy/render-env.sh b/deploy/render-env.sh new file mode 100755 index 0000000..4094841 --- /dev/null +++ b/deploy/render-env.sh @@ -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 </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 diff --git a/scripts/ci/compile-android.sh b/scripts/ci/compile-android.sh index d0d289c..7cc1acf 100755 --- a/scripts/ci/compile-android.sh +++ b/scripts/ci/compile-android.sh @@ -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 < 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 < compile-android: WARNING — no ANDROID_KEYSTORE_BASE64, falling back to debug signing" -fi # Build APK (universal, all ABIs — simplest for sideload download) cd client