chore: 固化 NAS 更新服务安装流程
CI / config (push) Canceled after 0s
CI / test-frontend (push) Canceled after 0s
CI / test-rust (push) Canceled after 0s
CI / test-e2e (push) Canceled after 0s
CI / test-e2e-release (push) Canceled after 0s
CI / build (push) Canceled after 0s
CI / release (push) Canceled after 0s
CI / docker (push) Canceled after 0s
CI / docker-website (push) Canceled after 0s

Co-Authored-By: Codex <noreply@anthropic.com>
This commit is contained in:
2026-08-12 23:16:26 +08:00
co-authored by Codex
parent 3a49d0efc0
commit 9938860d6b
3 changed files with 111 additions and 0 deletions
+4
View File
@@ -57,6 +57,10 @@ SSH 或 `sudo` 密码。安装时要完成以下动作:
6. 执行 `systemctl daemon-reload`,再手动启动一次服务,确认拉取、重建和健康检查
成功。服务不会常驻,只有本机发布脚本主动调用时才运行。
仓库内的 `install-update-service.sh` 会执行上述 NAS 安装步骤。它会先用 `visudo`
校验规则,保留现有 `.env` 的路径和 UID/GID,只把镜像标签改成 `edge`;脚本本身
不会拉取镜像、启动服务或重建容器。
部署 `.env` 不存放账号密码,保留以下字段:
```dotenv
+14
View File
@@ -13,6 +13,10 @@ const updateSudoers = readFileSync(
"deploy/nas/plainleaf-update.sudoers",
"utf8",
);
const updateInstaller = readFileSync(
"deploy/nas/install-update-service.sh",
"utf8",
);
test("NAS image allows automatic setup, multi-space, and legacy mode detection", () => {
expect(dockerfile).toContain('ENTRYPOINT ["/usr/local/bin/plainleaf"]');
@@ -72,3 +76,13 @@ test("root service only runs the Plainleaf updater when explicitly triggered", (
expect(publisher).not.toContain("StrictHostKeyChecking=no");
expect(publisher).not.toContain("sshpass");
});
test("one-time installer validates sudoers and restricts the publishing key", () => {
expect(updateInstaller).toContain(
'/usr/sbin/visudo -cf "${SOURCE_DIR}/plainleaf-update.sudoers"',
);
expect(updateInstaller).toContain('restrict,command=\\"${FORCED_COMMAND}\\"');
expect(updateInstaller).toContain("systemctl daemon-reload");
expect(updateInstaller).not.toContain("systemctl enable");
expect(updateInstaller).not.toMatch(/^systemctl start/m);
});
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env bash
set -Eeuo pipefail
if [[ "$EUID" -ne 0 ]]; then
echo "请使用 sudo 运行此安装脚本。" >&2
exit 1
fi
if [[ "$#" -ne 1 ]]; then
echo "用法:$0 <Plainleaf 专用 SSH 公钥>" >&2
exit 1
fi
readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly PUBLIC_KEY_FILE="$1"
readonly NAS_USER="13616066635"
readonly NAS_UID="1001"
readonly NAS_GID="1001"
readonly NAS_HOME="/home/${NAS_USER}"
readonly CURRENT_DEPLOY_DIR="/data_s001/data/udata/real/13616066635/docker/plainleaf"
readonly ROOT_CONFIG_DIR="/etc/plainleaf"
readonly AUTHORIZED_KEYS="${NAS_HOME}/.ssh/authorized_keys"
readonly FORCED_COMMAND='sudo -n /usr/bin/systemctl start plainleaf-update.service'
for required_file in \
compose.yaml \
update-plainleaf.sh \
plainleaf-update.service \
plainleaf-update.sudoers; do
if [[ ! -r "${SOURCE_DIR}/${required_file}" ]]; then
echo "缺少安装文件:${SOURCE_DIR}/${required_file}" >&2
exit 1
fi
done
if [[ ! -r "$PUBLIC_KEY_FILE" ]]; then
echo "无法读取 SSH 公钥:${PUBLIC_KEY_FILE}" >&2
exit 1
fi
read -r key_type key_body key_comment < "$PUBLIC_KEY_FILE"
if [[ "$key_type" != "ssh-ed25519" || -z "$key_body" ]]; then
echo "SSH 公钥必须是有效的 Ed25519 公钥。" >&2
exit 1
fi
if [[ ! -r "${CURRENT_DEPLOY_DIR}/.env" ]]; then
echo "找不到现有 Plainleaf 环境配置:${CURRENT_DEPLOY_DIR}/.env" >&2
exit 1
fi
/usr/sbin/visudo -cf "${SOURCE_DIR}/plainleaf-update.sudoers"
install -d -o root -g root -m 0700 "$ROOT_CONFIG_DIR"
install -o root -g root -m 0600 \
"${SOURCE_DIR}/compose.yaml" \
"${ROOT_CONFIG_DIR}/compose.yaml"
install -o root -g root -m 0600 \
"${CURRENT_DEPLOY_DIR}/.env" \
"${ROOT_CONFIG_DIR}/plainleaf.env"
if grep -q '^PLAINLEAF_IMAGE_TAG=' "${ROOT_CONFIG_DIR}/plainleaf.env"; then
sed -i 's/^PLAINLEAF_IMAGE_TAG=.*/PLAINLEAF_IMAGE_TAG=edge/' \
"${ROOT_CONFIG_DIR}/plainleaf.env"
else
printf '\nPLAINLEAF_IMAGE_TAG=edge\n' >> "${ROOT_CONFIG_DIR}/plainleaf.env"
fi
install -o root -g root -m 0700 \
"${SOURCE_DIR}/update-plainleaf.sh" \
/usr/local/sbin/plainleaf-update
install -o root -g root -m 0644 \
"${SOURCE_DIR}/plainleaf-update.service" \
/etc/systemd/system/plainleaf-update.service
install -o root -g root -m 0440 \
"${SOURCE_DIR}/plainleaf-update.sudoers" \
/etc/sudoers.d/plainleaf-update
install -d -o "$NAS_UID" -g "$NAS_GID" -m 0700 "$NAS_HOME"
install -d -o "$NAS_UID" -g "$NAS_GID" -m 0700 "${NAS_HOME}/.ssh"
touch "$AUTHORIZED_KEYS"
chown "${NAS_UID}:${NAS_GID}" "$AUTHORIZED_KEYS"
chmod 0600 "$AUTHORIZED_KEYS"
authorized_line="restrict,command=\"${FORCED_COMMAND}\" ${key_type} ${key_body} ${key_comment:-plainleaf-nas-publisher}"
if ! grep -Fqx "$authorized_line" "$AUTHORIZED_KEYS"; then
printf '%s\n' "$authorized_line" >> "$AUTHORIZED_KEYS"
fi
systemctl daemon-reload
echo "Plainleaf 主动更新服务安装完成。"