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
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:
@@ -57,6 +57,10 @@ SSH 或 `sudo` 密码。安装时要完成以下动作:
|
||||
6. 执行 `systemctl daemon-reload`,再手动启动一次服务,确认拉取、重建和健康检查
|
||||
成功。服务不会常驻,只有本机发布脚本主动调用时才运行。
|
||||
|
||||
仓库内的 `install-update-service.sh` 会执行上述 NAS 安装步骤。它会先用 `visudo`
|
||||
校验规则,保留现有 `.env` 的路径和 UID/GID,只把镜像标签改成 `edge`;脚本本身
|
||||
不会拉取镜像、启动服务或重建容器。
|
||||
|
||||
部署 `.env` 不存放账号密码,保留以下字段:
|
||||
|
||||
```dotenv
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
Executable
+93
@@ -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 主动更新服务安装完成。"
|
||||
Reference in New Issue
Block a user