复核 R-d6(sudo ./deploy.sh 时 DATA_DIR=~/… 展开成 /root 下):有 SUDO_USER 时 ~ 按它的家目录展开(getent passwd 取,取不到退回 $HOME),「不能是家目录本身」也按它查;install、upgrade、migrate 开头打印展开后的绝对路径(DATA_DIR 用了 ~ 时注明 ~ 是哪个目录)。deploy/README 写一句(agentlab.env 已有的行没动)。假 docker 单测:SUDO_USER 的家目录、取不到时退回 $HOME

This commit is contained in:
ThearchyHelios
2026-10-19 16:15:21 +08:00
parent 49118eeef2
commit 71b83195ac
3 changed files with 43 additions and 3 deletions
+21
View File
@@ -301,6 +301,27 @@ def test_more_than_one_worker_needs_postgres(tmp_path):
assert deploy.containers()[APP]["state"] == "running", "内置 PostgreSQL 时可以多进程"
def test_tilde_in_data_dir_is_the_sudo_users_home(tmp_path):
"""复核 R-d6:DATA_DIR=~/… 用 sudo 运行时按 SUDO_USER 的家目录展开(getent passwd 取),不是 /root;展开后的绝对路径打印出来。"""
deploy = Deploy(tmp_path, env_lines=["DATA_DIR=~/agentlab_data"])
alice = tmp_path / "home" / "alice"
alice.mkdir(parents=True)
root_home = tmp_path / "root"
root_home.mkdir()
getent = tmp_path / "bin" / "getent"
getent.write_text(f'#!/bin/sh\n[ "$1" = passwd ] && [ "$2" = alice ] && echo "alice:x:1000:1000::{alice}:/bin/bash"\n')
getent.chmod(0o755)
out = deploy("install", HOME=str(root_home), SUDO_USER="alice")
target = (alice / "agentlab_data").resolve()
assert target.is_dir() and not (root_home / "agentlab_data").exists()
assert f"数据目录:{target}(DATA_DIR=~/agentlab_data,~ 是 {alice})" in out.stdout
assert deploy.containers()[APP]["mounts"]["/data"] == str(target)
# 取不到 SUDO_USER 的家目录:退回 $HOME
other = Deploy(tmp_path / "other", env_lines=["DATA_DIR=~/agentlab_data"], name="agl-b")
other("install", HOME=str(root_home), SUDO_USER="nobody-here")
assert (root_home / "agentlab_data").is_dir()
def test_install_postgres_refuses_a_leftover_volume(deploy):
deploy.state_file.write_text(json.dumps({"images": {}, "containers": {}, "networks": [], "volumes": [VOL]}))
out = deploy("install", "--postgres", ok=False)
+4
View File
@@ -85,6 +85,10 @@ sudo cp -rp data/backups/sqlite/<时间>/records/. data/records/ # 记
`-wal`、`-shm` 要先删:留着的话 SQLite 会把它们当成换回来的库的一部分。
`DATA_DIR` 写成 `~/…` 时,`~` 是运行 deploy.sh 的那个人的家目录:用 `sudo ./deploy.sh` 运行时按调用 sudo 的用户
(`SUDO_USER`)的家目录展开,不是 `/root`。`install`、`upgrade` 开头会打印展开后的绝对路径(`==> 数据目录:…`),对一眼;
不放心就直接写绝对路径。
deploy.sh 会把数据目录的属主改成容器里的用户(uid 10001),所以备份、删除要用 sudo。
停下来备份最稳妥(以默认的 `./data` 为例,在包目录里执行):
+18 -3
View File
@@ -215,15 +215,29 @@ read_env() {
case "$ENABLE_MICROVM" in auto|0|1) ;; *) die "ENABLE_MICROVM 只能是 auto、0 或 1:$ENABLE_MICROVM" ;; esac
# 相对路径以 deploy.sh 所在的目录为准,和从哪里运行无关
# 下面比较的就是字面上的 ~,不需要展开
# 下面比较的就是字面上的 ~,不需要展开。~ 是运行 deploy.sh 的那个人的家目录:sudo ./deploy.sh 时 $HOME 常是 /root,
# 按 SUDO_USER 的家目录展开(见 invoking_home)
INVOKER_HOME="$(invoking_home)"
TILDE_NOTE=""
# shellcheck disable=SC2088
case "$DATA_DIR" in
/*) DATA_PATH="$DATA_DIR" ;;
"~"|"~/"*) DATA_PATH="$HOME${DATA_DIR#\~}" ;;
"~"|"~/"*)
DATA_PATH="$INVOKER_HOME${DATA_DIR#\~}"
TILDE_NOTE="(DATA_DIR=${DATA_DIR},~ 是 ${INVOKER_HOME})" ;;
*) DATA_PATH="$HERE/${DATA_DIR#./}" ;;
esac
}
# 家目录:用 sudo 运行时是调用 sudo 的那个人的(getent passwd 取),取不到退回 $HOME
invoking_home() {
local home=""
if [ -n "${SUDO_USER:-}" ] && [ "$SUDO_USER" != root ] && command -v getent >/dev/null 2>&1; then
home="$(getent passwd "$SUDO_USER" 2>/dev/null | cut -d: -f6 || true)"
fi
printf '%s' "${home:-$HOME}"
}
# ---------------------------------------------------------------------------
# docker 与镜像
# ---------------------------------------------------------------------------
@@ -307,7 +321,8 @@ prepare_data() {
/|/bin|/boot|/dev|/etc|/home|/lib|/opt|/proc|/root|/sbin|/srv|/sys|/usr|/var)
die "DATA_DIR 不能是系统目录:$DATA_ABS" ;;
esac
[ "$DATA_ABS" != "$HOME" ] || die "DATA_DIR 不能是家目录本身:$DATA_ABS"
[ "$DATA_ABS" != "$HOME" ] && [ "$DATA_ABS" != "${INVOKER_HOME:-$HOME}" ] || die "DATA_DIR 不能是家目录本身:$DATA_ABS"
say "数据目录:${DATA_ABS}${TILDE_NOTE:-}"
}
# 已经有同名容器时:它得是 AgentLab 的,数据目录也得和配置的是同一个。