比较提交

...

2 次代码提交

作者 SHA1 备注 提交日期
徐勤民
872a3331de fix(update): keep optional mail health non-blocking 2026-07-28 22:05:20 +08:00
徐勤民
7912b6a527 feat(deploy): provision store monitoring secrets 2026-07-28 19:53:39 +08:00
共有 9 个文件被更改,包括 78 次插入1 次删除

查看文件

@ -31,6 +31,7 @@ REGISTRY_USER=
# 镜像版本标签,与业务发布版本一一对应
# 开发/体验环境可用 latest;生产环境请固定版本号
IMAGE_TAG=latest
MANAGEMENT_HEALTH_MAIL_ENABLED=false
# =============================================================================
# 服务 Profile — 选择要启动哪些容器

查看文件

@ -60,6 +60,15 @@ XUQM_JWT_SECRET=
# 留空时 install.sh 自动生成
SDK_INTERNAL_TOKEN=
# =============================================================================
# 应用商店监测 Secrets 主密钥
# =============================================================================
# 32 字节随机值的 Base64。用于 AES-256-GCM 加密商店监测凭据和 Webhook 密钥。
# 首次安装自动生成;丢失后无法解密已有凭据,禁止跨公有化/私有化部署复用。
XUQM_STORE_SECRET_MASTER_KEY=
XUQM_STORE_SECRET_KEY_VERSION=v1
# =============================================================================
# SMTP 邮件密码(发送验证码邮件)
# =============================================================================

查看文件

@ -152,6 +152,7 @@ services:
env_file:
- ./config/xuqm.env
- ./config/secrets.env
- ./config/mail/smtp.env
- ./config/vendors/store-submit.env # 各应用市场发布凭据
environment:
SPRING_DATASOURCE_URL: "jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT:-3306}/${MYSQL_DATABASE:-xuqm_private}?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true"
@ -159,6 +160,8 @@ services:
SDK_TENANT_SERVICE_URL: "http://tenant-service:9001"
FILE_BASE_URL: "${CONSOLE_DOMAIN}"
FILE_SERVICE_INTERNAL_URL: "http://file-service:8086"
# 邮件通知默认关闭;没有 SMTP 配置时不应让 update-service 整体健康检查失败。
MANAGEMENT_HEALTH_MAIL_ENABLED: "${MANAGEMENT_HEALTH_MAIL_ENABLED:-false}"
volumes:
- ./data/update:/data/update # 版本包存储目录
restart: unless-stopped

查看文件

@ -29,6 +29,8 @@
| `REDIS_PASSWORD` | Redis 密码 |
| `SPRING_DATASOURCE_PASSWORD` | Spring 读取的数据库密码(与 `MYSQL_PASSWORD` 值相同) |
| `SPRING_DATA_REDIS_PASSWORD` | Spring 读取的 Redis 密码(与 `REDIS_PASSWORD` 值相同) |
| `XUQM_STORE_SECRET_MASTER_KEY` | 商店监测凭据 AES-256-GCM 主密钥32 字节 Base64 |
| `XUQM_STORE_SECRET_KEY_VERSION` | 主密钥版本标识,默认 `v1` |
> **设计说明**Spring 通过 `env_file` 直接读取 `SPRING_DATASOURCE_PASSWORD`,而非通过 `docker-compose.yml``environment:` 节替换 `${MYSQL_PASSWORD}`。这是因为 compose 变量替换在 shell 中找不到该变量时会替换为空字符串,导致"Access denied (using password: NO)"。旧版部署如缺少这两个字段,`reset.sh` 和 `update.sh` 会自动补齐。
@ -133,7 +135,11 @@ Web 代理会覆盖上游缓存头:入口 HTML、manifest 和普通路由使
## `config/mail/smtp.env`
邮件服务配置,不填则邮件功能不可用,不影响其他服务启动。
邮件服务配置,不填则邮件功能不可用,不影响其他服务启动。`tenant-service`
用于账号邮件,`update-service` 用于租户显式启用的商店状态邮件通知;通知默认关闭,
未配置 SMTP 时 `MANAGEMENT_HEALTH_MAIL_ENABLED=false`,不会使更新服务整体健康状态
变为 DOWN。启用邮件通知并完成 SMTP 配置后,可设为 `true` 将邮件连接纳入健康检查。
邮件发送失败不得影响商店状态同步和平台主流程。
---

查看文件

@ -157,6 +157,17 @@ set_env_value "$ROOT_DIR/config/secrets.env" "MYSQL_PASSWORD" "$MYSQL_PASSWORD"
[ -n "${MYSQL_ROOT_PASSWORD:-}" ] && \
set_env_value "$ROOT_DIR/config/secrets.env" "MYSQL_ROOT_PASSWORD" "$MYSQL_ROOT_PASSWORD"
set_env_value "$ROOT_DIR/config/secrets.env" "REDIS_PASSWORD" "$REDIS_PASSWORD"
set_env_value "$ROOT_DIR/config/secrets.env" "SPRING_DATASOURCE_PASSWORD" "$MYSQL_PASSWORD"
set_env_value "$ROOT_DIR/config/secrets.env" "SPRING_DATA_REDIS_PASSWORD" "$REDIS_PASSWORD"
ensure_env_value "$ROOT_DIR/config/secrets.env" "XUQM_JWT_SECRET" \
"${XUQM_JWT_SECRET:-}" "$(random_secret)$(random_secret)" >/dev/null
ensure_env_value "$ROOT_DIR/config/secrets.env" "SDK_INTERNAL_TOKEN" \
"${SDK_INTERNAL_TOKEN:-}" "$(random_secret)" >/dev/null
ensure_env_value "$ROOT_DIR/config/secrets.env" "XUQM_STORE_SECRET_MASTER_KEY" \
"${XUQM_STORE_SECRET_MASTER_KEY:-}" "$(random_aes256_base64)" >/dev/null
set_env_value "$ROOT_DIR/config/secrets.env" "XUQM_STORE_SECRET_KEY_VERSION" \
"${XUQM_STORE_SECRET_KEY_VERSION:-v1}"
chmod 600 "$ROOT_DIR/config/secrets.env"
"$ROOT_DIR/scripts/render-config.sh"

查看文件

@ -380,6 +380,15 @@ EOF
ok ".env 已写入"
# config/secrets.env — 敏感信息(权限 600
if command -v openssl >/dev/null 2>&1; then
XUQM_JWT_SECRET="$(openssl rand -base64 48 | tr -d '\n')"
SDK_INTERNAL_TOKEN="$(openssl rand -base64 32 | tr -d '\n')"
XUQM_STORE_SECRET_MASTER_KEY="$(openssl rand -base64 32 | tr -d '\n')"
else
XUQM_JWT_SECRET="$(dd if=/dev/urandom bs=48 count=1 2>/dev/null | base64 | tr -d '\n')"
SDK_INTERNAL_TOKEN="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n')"
XUQM_STORE_SECRET_MASTER_KEY="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n')"
fi
mkdir -p "$ROOT_DIR/config"
cat > "$ROOT_DIR/config/secrets.env" <<EOF
# XuqmGroup 私有化部署 — 敏感凭据请妥善保管,chmod 600
@ -389,6 +398,10 @@ REDIS_PASSWORD=${REDIS_PASSWORD}
# Spring 直接读取的 env 名(避免 docker compose 变量替换时因 shell 缺失变量而变成空字符串)
SPRING_DATASOURCE_PASSWORD=${MYSQL_PASSWORD}
SPRING_DATA_REDIS_PASSWORD=${REDIS_PASSWORD}
XUQM_JWT_SECRET=${XUQM_JWT_SECRET}
SDK_INTERNAL_TOKEN=${SDK_INTERNAL_TOKEN}
XUQM_STORE_SECRET_MASTER_KEY=${XUQM_STORE_SECRET_MASTER_KEY}
XUQM_STORE_SECRET_KEY_VERSION=v1
EOF
chmod 600 "$ROOT_DIR/config/secrets.env"
ok "config/secrets.env 已写入 (chmod 600)"

查看文件

@ -60,6 +60,14 @@ random_secret() {
fi
}
random_aes256_base64() {
if command -v openssl >/dev/null 2>&1; then
openssl rand -base64 32 | tr -d '\n'
else
dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n'
fi
}
ensure_secret_file() {
if [ ! -f "$ROOT_DIR/config/secrets.env" ]; then
cp "$ROOT_DIR/config/secrets.env.example" "$ROOT_DIR/config/secrets.env"

查看文件

@ -90,6 +90,18 @@ if ! grep -q "^SPRING_DATA_REDIS_PASSWORD=" "$ROOT_DIR/config/secrets.env" 2>/de
fi
[ "$_patched" -eq 1 ] && ok "secrets.env 已补齐 SPRING_DATASOURCE_PASSWORD / SPRING_DATA_REDIS_PASSWORD"
if ! grep -q "^XUQM_STORE_SECRET_MASTER_KEY=." "$ROOT_DIR/config/secrets.env" 2>/dev/null; then
if command -v openssl >/dev/null 2>&1; then
_store_master_key="$(openssl rand -base64 32 | tr -d '\n')"
else
_store_master_key="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n')"
fi
printf 'XUQM_STORE_SECRET_MASTER_KEY=%s\n' "$_store_master_key" >> "$ROOT_DIR/config/secrets.env"
printf 'XUQM_STORE_SECRET_KEY_VERSION=v1\n' >> "$ROOT_DIR/config/secrets.env"
chmod 600 "$ROOT_DIR/config/secrets.env"
ok "secrets.env 已生成应用商店监测加密主密钥"
fi
_CONSOLE_DOMAIN="$(grep '^CONSOLE_DOMAIN=' "$ROOT_DIR/config/xuqm.env" 2>/dev/null \
| cut -d= -f2- | tr -d '"' | tr -d "'")"
ok "CONSOLE_DOMAIN=${_CONSOLE_DOMAIN:-(未设置)}"

查看文件

@ -123,6 +123,20 @@ if ! grep -q "^SPRING_DATA_REDIS_PASSWORD=" "$ROOT_DIR/config/secrets.env" 2>/de
fi
[ "$_patched" -eq 1 ] && ok "secrets.env 已补齐 SPRING_DATASOURCE_PASSWORD / SPRING_DATA_REDIS_PASSWORD"
# 商店监测凭据使用独立的 AES-256-GCM 主密钥。升级旧部署时只生成一次,
# 后续更新必须保留原值,否则已有商店凭据将无法解密。
if ! grep -q "^XUQM_STORE_SECRET_MASTER_KEY=." "$ROOT_DIR/config/secrets.env" 2>/dev/null; then
if command -v openssl >/dev/null 2>&1; then
_store_master_key="$(openssl rand -base64 32 | tr -d '\n')"
else
_store_master_key="$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d '\n')"
fi
printf 'XUQM_STORE_SECRET_MASTER_KEY=%s\n' "$_store_master_key" >> "$ROOT_DIR/config/secrets.env"
printf 'XUQM_STORE_SECRET_KEY_VERSION=v1\n' >> "$ROOT_DIR/config/secrets.env"
chmod 600 "$ROOT_DIR/config/secrets.env"
ok "secrets.env 已生成应用商店监测加密主密钥"
fi
# 迁移:补齐 PRIVATE_DEPLOY_ROOT一键更新功能需要此变量,旧版部署升级时自动写入
if ! grep -q "^PRIVATE_DEPLOY_ROOT=" "$ROOT_DIR/.env" 2>/dev/null; then
printf '\nPRIVATE_DEPLOY_ROOT=%s\n' "$ROOT_DIR" >> "$ROOT_DIR/.env"