feat: 工作流一点小优化
This commit is contained in:
1 parent
15220ab225
commit
adf13ce819
2 files changed
+15
-303
No files matched your search
@@ -74,12 +74,20 @@ jobs:
|
||||
cp "$CONFIG_FILE" wrangler.toml
|
||||
fi
|
||||
|
||||
# 注入 Cloudflare Workers 名称
|
||||
- name: Inject Workers Name
|
||||
env:
|
||||
CONFIG_FILE: ${{ env.WRANGLER_CONFIG || 'wrangler.toml' }}
|
||||
CLOUDFLARE_WORKERS_NAME: ${{ secrets.CLOUDFLARE_WORKERS_NAME || '2fauth-worker' }}
|
||||
run: |
|
||||
sed -i "0,/name =/s/name = \".*\"/name = \"$CLOUDFLARE_WORKERS_NAME\"/" "wrangler.toml"
|
||||
|
||||
# 注入 D1 数据库配置
|
||||
- name: Inject D1 Database ID
|
||||
env:
|
||||
CONFIG_FILE: ${{ env.WRANGLER_CONFIG || 'wrangler.toml' }}
|
||||
CLOUDFLARE_D1_DATABASE_ID: ${{ secrets.CLOUDFLARE_D1_DATABASE_ID }}
|
||||
CLOUDFLARE_D1_DATABASE_NAME: ${{ secrets.CLOUDFLARE_D1_DATABASE_NAME || '2fauth-db' }}
|
||||
CLOUDFLARE_D1_DATABASE_NAME: ${{ secrets.CLOUDFLARE_D1_DATABASE_NAME || 'nodeauth-db' }}
|
||||
run: |
|
||||
sed -i '/^\[\[d1_databases\]\]/d; /^[[:space:]]*database_name[[:space:]]*=/d; /^[[:space:]]*database_id[[:space:]]*=/d; /^[[:space:]]*binding[[:space:]]*=[[:space:]]*"DB"/d' wrangler.toml
|
||||
if grep -q "\[env.dev\]" wrangler.toml; then
|
||||
@@ -93,7 +101,7 @@ jobs:
|
||||
with:
|
||||
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
command: d1 execute ${{ secrets.CLOUDFLARE_D1_DATABASE_NAME || '2fauth-db' }} --remote --file=backend/schema.sql
|
||||
command: d1 execute ${{ secrets.CLOUDFLARE_D1_DATABASE_NAME || 'nodeauth-db' }} --remote --file=backend/schema.sql
|
||||
|
||||
# 动态生成 Secrets 列表 (仅包含已配置的变量)
|
||||
- name: Generate Secret List
|
||||
@@ -123,6 +131,8 @@ jobs:
|
||||
OAUTH_BAIDU_CLIENT_SECRET: ${{ secrets.OAUTH_BAIDU_CLIENT_SECRET }}
|
||||
OAUTH_DROPBOX_CLIENT_ID: ${{ secrets.OAUTH_DROPBOX_CLIENT_ID }}
|
||||
OAUTH_DROPBOX_CLIENT_SECRET: ${{ secrets.OAUTH_DROPBOX_CLIENT_SECRET }}
|
||||
OAUTH_WALLETCONNECT_PROJECT_ID: ${{ secrets.OAUTH_WALLETCONNECT_PROJECT_ID }}
|
||||
OAUTH_WALLETCONNECT_SELF_PROXY: ${{ secrets.OAUTH_WALLETCONNECT_SELF_PROXY }}
|
||||
|
||||
run: |
|
||||
SECRETS="
|
||||
@@ -141,6 +151,7 @@ jobs:
|
||||
"OAUTH_MICROSOFT_CLIENT_ID" "OAUTH_MICROSOFT_CLIENT_SECRET"
|
||||
"OAUTH_BAIDU_CLIENT_ID" "OAUTH_BAIDU_CLIENT_SECRET"
|
||||
"OAUTH_DROPBOX_CLIENT_ID" "OAUTH_DROPBOX_CLIENT_SECRET"
|
||||
"OAUTH_WALLETCONNECT_PROJECT_ID" "OAUTH_WALLETCONNECT_SELF_PROXY"
|
||||
)
|
||||
|
||||
for VAR in "${OPTIONAL_VARS[@]}"; do
|
||||
@@ -195,6 +206,8 @@ jobs:
|
||||
OAUTH_BAIDU_CLIENT_SECRET: ${{ secrets.OAUTH_BAIDU_CLIENT_SECRET }}
|
||||
OAUTH_DROPBOX_CLIENT_ID: ${{ secrets.OAUTH_DROPBOX_CLIENT_ID }}
|
||||
OAUTH_DROPBOX_CLIENT_SECRET: ${{ secrets.OAUTH_DROPBOX_CLIENT_SECRET }}
|
||||
OAUTH_WALLETCONNECT_PROJECT_ID: ${{ secrets.OAUTH_WALLETCONNECT_PROJECT_ID }}
|
||||
OAUTH_WALLETCONNECT_SELF_PROXY: ${{ secrets.OAUTH_WALLETCONNECT_SELF_PROXY }}
|
||||
ENCRYPTION_KEY: ${{ secrets.ENCRYPTION_KEY }}
|
||||
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
||||
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
name: Backup Cloudflare D1 Database And R2 Bucket via Rclone
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 5 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
rclone:
|
||||
name: Secure Backup Pipeline
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# --- 全局配置 ---
|
||||
TZ: 'Asia/Shanghai'
|
||||
|
||||
# --- Cloudflare ---
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
|
||||
# --- Cloudflare D1 Database ---
|
||||
CLOUDFLARE_D1_DATABASE_ID: ${{ secrets.CLOUDFLARE_D1_DATABASE_ID }}
|
||||
CLOUDFLARE_D1_DATABASE_NAME: ${{ secrets.CLOUDFLARE_D1_DATABASE_NAME }}
|
||||
|
||||
# --- Cloudflare R2 Storage ---
|
||||
CLOUDFLARE_R2_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
|
||||
CLOUDFLARE_R2_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
|
||||
CLOUDFLARE_R2_BUCKET_NAME: ${{ secrets.CLOUDFLARE_R2_BUCKET_NAME }}
|
||||
|
||||
# --- Cloudflare Zero Trust (Service Token) ---
|
||||
CLOUDFLARE_ACCESS_CLIENT_ID: ${{ secrets.CLOUDFLARE_ACCESS_CLIENT_ID }}
|
||||
CLOUDFLARE_ACCESS_CLIENT_SECRET: ${{ secrets.CLOUDFLARE_ACCESS_CLIENT_SECRET }}
|
||||
|
||||
# --- Encryption and Retention Policy ---
|
||||
BACKUP_ENCRYPTION_KEY: ${{ secrets.BACKUP_ENCRYPTION_KEY }}
|
||||
RETENTION_DAYS: ${{ secrets.BACKUP_RETENTION_DAYS || 30 }}
|
||||
|
||||
# --- WebDAV ---
|
||||
WEBDAV_URL: ${{ secrets.WEBDAV_URL }}
|
||||
WEBDAV_USER: ${{ secrets.WEBDAV_USER }}
|
||||
WEBDAV_PASSWORD: ${{ secrets.WEBDAV_PASSWORD }}
|
||||
WEBDAV_VENDOR: ${{ secrets.WEBDAV_VENDOR || 'other' }}
|
||||
WEBDAV_BASE_PATH: ${{ secrets.WEBDAV_BASE_PATH }}
|
||||
|
||||
# --- Google Drive ---
|
||||
GDRIVE_TOKEN: ${{ secrets.GDRIVE_TOKEN }}
|
||||
GDRIVE_CLIENT_ID: ${{ secrets.GDRIVE_CLIENT_ID }}
|
||||
GDRIVE_CLIENT_SECRET: ${{ secrets.GDRIVE_CLIENT_SECRET }}
|
||||
GDRIVE_ROOT_FOLDER_ID: ${{ secrets.GDRIVE_ROOT_FOLDER_ID }}
|
||||
|
||||
# --- 工具版本 ---
|
||||
WRANGLER_VERSION: "3.57.1"
|
||||
|
||||
steps:
|
||||
# STEP 1: 安装 Rclone
|
||||
- name: 🛠️ Setup Tools
|
||||
uses: AnimMouse/setup-rclone@02a3642a1ad72d5b765f48873141b9f26e9082f1 # v1
|
||||
with:
|
||||
version: v1.66.0
|
||||
|
||||
# STEP 2: 检查配置并注入环境变量
|
||||
# 将 Rclone 配置直接写入环境变量 (内存配置),不生成实体配置文件
|
||||
- name: 🛡️ Pre-flight Check & Config Injection
|
||||
id: config
|
||||
run: |
|
||||
# 初始化目标列表
|
||||
TARGETS=""
|
||||
|
||||
# 获取仓库名称 (用于默认路径)
|
||||
REPO_NAME="${GITHUB_REPOSITORY#*/}"
|
||||
|
||||
# --- 1. 检查 Cloudflare 凭据 ---
|
||||
if [[ -z "$CLOUDFLARE_ACCOUNT_ID" || -z "$CLOUDFLARE_API_TOKEN" ]]; then
|
||||
echo "::error::Missing Cloudflare credentials!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- 2. 配置 WebDAV ---
|
||||
if [[ -n "$WEBDAV_URL" && -n "$WEBDAV_USER" && -n "$WEBDAV_PASSWORD" ]]; then
|
||||
echo "✅ WebDAV Detected: Enabling..."
|
||||
|
||||
TARGETS+="remote_webdav "
|
||||
|
||||
# 注入 Rclone WebDAV 配置
|
||||
echo "RCLONE_CONFIG_REMOTE_WEBDAV_TYPE=webdav" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_WEBDAV_URL=$WEBDAV_URL" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_WEBDAV_VENDOR=$WEBDAV_VENDOR" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_WEBDAV_USER=$WEBDAV_USER" >> $GITHUB_ENV
|
||||
|
||||
# 设置 WebDAV 默认路径
|
||||
if [[ -z "$WEBDAV_BASE_PATH" ]]; then
|
||||
WEBDAV_BASE_PATH="$REPO_NAME"
|
||||
echo "WEBDAV_BASE_PATH=$REPO_NAME" >> $GITHUB_ENV
|
||||
echo "ℹ️ WEBDAV_BASE_PATH auto-set to: $REPO_NAME"
|
||||
fi
|
||||
|
||||
# 加密 WebDAV 密码
|
||||
OBSCURED=$(rclone obscure "$WEBDAV_PASSWORD")
|
||||
echo "RCLONE_CONFIG_REMOTE_WEBDAV_PASS=$OBSCURED" >> $GITHUB_ENV
|
||||
|
||||
# 配置 Cloudflare Access 请求头
|
||||
if [[ -n "$CLOUDFLARE_ACCESS_CLIENT_ID" && -n "$CLOUDFLARE_ACCESS_CLIENT_SECRET" ]]; then
|
||||
echo "🛡️ Cloudflare Access Token Detected: Configuring headers..."
|
||||
echo "RCLONE_CONFIG_REMOTE_WEBDAV_HEADERS=CF-Access-Client-Id,$CLOUDFLARE_ACCESS_CLIENT_ID,CF-Access-Client-Secret,$CLOUDFLARE_ACCESS_CLIENT_SECRET" >> $GITHUB_ENV
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 3. 配置 Google Drive ---
|
||||
if [[ -n "$GDRIVE_TOKEN" && -n "$GDRIVE_CLIENT_ID" && -n "$GDRIVE_CLIENT_SECRET" ]]; then
|
||||
echo "✅ GDrive Detected: Enabling..."
|
||||
TARGETS+="remote_gdrive "
|
||||
|
||||
echo "RCLONE_CONFIG_REMOTE_GDRIVE_TYPE=drive" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_GDRIVE_SCOPE=drive" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_GDRIVE_TOKEN=$GDRIVE_TOKEN" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_GDRIVE_CLIENT_ID=$GDRIVE_CLIENT_ID" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_GDRIVE_CLIENT_SECRET=$GDRIVE_CLIENT_SECRET" >> $GITHUB_ENV
|
||||
|
||||
if [[ -n "$GDRIVE_ROOT_FOLDER_ID" ]]; then
|
||||
echo "RCLONE_CONFIG_REMOTE_GDRIVE_ROOT_FOLDER_ID=$GDRIVE_ROOT_FOLDER_ID" >> $GITHUB_ENV
|
||||
echo "GDRIVE_BASE_PATH=" >> $GITHUB_ENV
|
||||
else
|
||||
# 若未设置 Root Folder ID,使用仓库名作为子目录
|
||||
echo "GDRIVE_BASE_PATH=$REPO_NAME/" >> $GITHUB_ENV
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- 4. 配置 Cloudflare R2 源 ---
|
||||
if [[ -n "$CLOUDFLARE_R2_ACCESS_KEY_ID" && -n "$CLOUDFLARE_R2_SECRET_ACCESS_KEY" ]]; then
|
||||
echo "✅ Cloudflare R2 Credentials Detected: Configuring..."
|
||||
|
||||
echo "RCLONE_CONFIG_REMOTE_R2_TYPE=s3" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_R2_PROVIDER=Cloudflare" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_R2_ACCESS_KEY_ID=$CLOUDFLARE_R2_ACCESS_KEY_ID" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_R2_SECRET_ACCESS_KEY=$CLOUDFLARE_R2_SECRET_ACCESS_KEY" >> $GITHUB_ENV
|
||||
echo "RCLONE_CONFIG_REMOTE_R2_ENDPOINT=https://$CLOUDFLARE_ACCOUNT_ID.r2.cloudflarestorage.com" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
# --- 5. 检查是否有可用备份目标 ---
|
||||
if [[ -z "$TARGETS" ]]; then
|
||||
echo "::error::No backup targets configured! Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 输出目标列表
|
||||
echo "BACKUP_TARGETS=$TARGETS" >> $GITHUB_ENV
|
||||
|
||||
# STEP 3: 导出并处理 D1 数据库
|
||||
- name: 📦 Export & Encrypt Cloudflare D1 Database
|
||||
run: |
|
||||
# 安装 Wrangler
|
||||
npm install -g wrangler@${{ env.WRANGLER_VERSION }} --quiet
|
||||
|
||||
# 获取数据库名称 (优先使用配置名,否则通过 ID 查询)
|
||||
if [[ -n "$CLOUDFLARE_D1_DATABASE_NAME" ]]; then
|
||||
echo "✅ Using configured D1 Database Name: $CLOUDFLARE_D1_DATABASE_NAME"
|
||||
DB_NAME="$CLOUDFLARE_D1_DATABASE_NAME"
|
||||
elif [[ -n "$CLOUDFLARE_D1_DATABASE_ID" ]]; then
|
||||
echo "🔍 Resolving D1 Database Name from ID: $CLOUDFLARE_D1_DATABASE_ID"
|
||||
DB_NAME=$(npx wrangler d1 list --json | jq -r ".[] | select(.uuid == \"$CLOUDFLARE_D1_DATABASE_ID\") | .name")
|
||||
if [[ -z "$DB_NAME" || "$DB_NAME" == "null" ]]; then
|
||||
echo "::error::Could not resolve D1 Name from UUID. Please check ID or configure CLOUDFLARE_D1_DATABASE_NAME."
|
||||
exit 1
|
||||
fi
|
||||
echo "CLOUDFLARE_D1_DATABASE_NAME=$DB_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
echo "::error::Neither CLOUDFLARE_D1_DATABASE_NAME nor CLOUDFLARE_D1_DATABASE_ID is configured!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🚀 Exporting: $DB_NAME"
|
||||
npx wrangler d1 export "$DB_NAME" --remote --output=backup.sql
|
||||
|
||||
echo "🗜️ Compressing..."
|
||||
gzip -9 backup.sql
|
||||
|
||||
# 生成带时间戳的文件名
|
||||
DATE=$(date +'%Y-%m-%d_%H-%M-%S')
|
||||
|
||||
if [[ -n "$BACKUP_ENCRYPTION_KEY" ]]; then
|
||||
echo "🔒 Encrypting (AES-256)..."
|
||||
FILENAME="backup_${DATE}.sql.gz.enc"
|
||||
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 \
|
||||
-in backup.sql.gz -out "$FILENAME" -pass pass:"$BACKUP_ENCRYPTION_KEY"
|
||||
else
|
||||
echo "⚠️ Encryption skipped (Key not set)"
|
||||
FILENAME="backup_${DATE}.sql.gz"
|
||||
mv backup.sql.gz "$FILENAME"
|
||||
fi
|
||||
|
||||
echo "FILENAME=$FILENAME" >> $GITHUB_ENV
|
||||
|
||||
# STEP 4: 同步 D1 备份文件
|
||||
- name: 🔄 Sync Cloudflare D1 Database to Cloud
|
||||
run: |
|
||||
# 允许单次失败,避免中断整个流程
|
||||
set +e
|
||||
|
||||
OVERALL_STATUS=0
|
||||
|
||||
for target in $BACKUP_TARGETS; do
|
||||
echo "---------------------------------------------------"
|
||||
echo "📡 Processing Remote: [${target}]"
|
||||
|
||||
# --- 确定目标路径 ---
|
||||
if [[ "$target" == "remote_webdav" ]]; then
|
||||
# WebDAV: 使用 d1-backup 子目录,防止误删
|
||||
DEST_PATH="${target}:${WEBDAV_BASE_PATH}/d1-backup/${CLOUDFLARE_D1_DATABASE_NAME}/${FILENAME}"
|
||||
PURGE_PATH="${target}:${WEBDAV_BASE_PATH}/d1-backup/${CLOUDFLARE_D1_DATABASE_NAME}/"
|
||||
else
|
||||
# GDrive: 使用 d1-backup 子目录
|
||||
DEST_PATH="${target}:${GDRIVE_BASE_PATH}d1-backup/${CLOUDFLARE_D1_DATABASE_NAME}/${FILENAME}"
|
||||
PURGE_PATH="${target}:${GDRIVE_BASE_PATH}d1-backup/${CLOUDFLARE_D1_DATABASE_NAME}/"
|
||||
fi
|
||||
|
||||
# --- 1. 执行上传 ---
|
||||
echo " 📤 Uploading..."
|
||||
rclone --config /dev/null copyto "$FILENAME" "$DEST_PATH" --retries 3 --user-agent "Mozilla/5.0"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "::error::❌ Failed to upload to $target"
|
||||
OVERALL_STATUS=1
|
||||
continue # 跳过当前目标的后续步骤,继续下一个目标
|
||||
fi
|
||||
|
||||
# --- 2. 清理旧备份 ---
|
||||
echo " 🧹 Pruning old backups (> ${RETENTION_DAYS}d)..."
|
||||
rclone --config /dev/null delete "$PURGE_PATH" --min-age ${RETENTION_DAYS}d -v
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "::warning::⚠️ Cleanup failed for $target, but upload was successful."
|
||||
# 清理失败不算核心失败,不修改 OVERALL_STATUS
|
||||
fi
|
||||
|
||||
echo " ✅ Success: $target"
|
||||
done
|
||||
|
||||
echo "---------------------------------------------------"
|
||||
|
||||
# 检查整体状态
|
||||
if [ $OVERALL_STATUS -ne 0 ]; then
|
||||
echo "::error::One or more backup targets failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 D1 backup tasks completed successfully."
|
||||
|
||||
# STEP 5: 同步 R2 存储桶
|
||||
- name: 🔄 Sync Cloudflare R2 Bucket to Cloud
|
||||
# R2 配置存在且有目标时运行 (即使 D1 失败也执行)
|
||||
if: ${{ !cancelled() && env.CLOUDFLARE_R2_BUCKET_NAME != '' && env.CLOUDFLARE_R2_ACCESS_KEY_ID != '' && env.BACKUP_TARGETS != '' }}
|
||||
run: |
|
||||
# 允许单次失败
|
||||
set +e
|
||||
|
||||
OVERALL_STATUS=0
|
||||
|
||||
echo "---------------------------------------------------"
|
||||
echo "📡 Syncing R2 Bucket: [$CLOUDFLARE_R2_BUCKET_NAME]"
|
||||
|
||||
for target in $BACKUP_TARGETS; do
|
||||
echo " ➡️ Target: $target"
|
||||
|
||||
# --- 确定目标路径 ---
|
||||
if [[ "$target" == "remote_webdav" ]]; then
|
||||
DEST_PATH="${target}:${WEBDAV_BASE_PATH}/r2-backup/${CLOUDFLARE_R2_BUCKET_NAME}"
|
||||
else
|
||||
DEST_PATH="${target}:${GDRIVE_BASE_PATH}r2-backup/${CLOUDFLARE_R2_BUCKET_NAME}"
|
||||
fi
|
||||
|
||||
rclone --config /dev/null sync "remote_r2:$CLOUDFLARE_R2_BUCKET_NAME" "$DEST_PATH" \
|
||||
--verbose \
|
||||
--transfers 16 \
|
||||
--checkers 8 \
|
||||
--retries 3 \
|
||||
--user-agent "Mozilla/5.0"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "::error::❌ Failed to sync R2 to $target"
|
||||
OVERALL_STATUS=1
|
||||
else
|
||||
echo " ✅ Success: $target"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $OVERALL_STATUS -ne 0 ]; then
|
||||
echo "::error::One or more R2 sync targets failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🎉 R2 Sync tasks completed."
|
||||
|
||||
# STEP 6: 清理本地临时文件
|
||||
- name: 🧹 Clean up local temp files
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
echo "Cleaning up local backup files..."
|
||||
rm -f backup*.sql.gz* backup.sql
|
||||
echo "✅ Cleanup done."
|
||||
Reference in new issue
Block a user